text:
package org.rarefiedredis.redis;

import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.List;

public class RedisMockHashTest {

    @Test public void hdelShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hdel(k, f);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
        }
        catch (Exception e) {
            assertEquals(false, true);
        }
        try {
            redis.hdel(k, f, f, f);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hdelShouldReturnZeroIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(0L, (long)redis.hdel(k, f));
    }

    @Test public void hdelShouldReturnZeroIfFieldDoesNotExistInKey() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field", f1 = "f1", f2 = "f2";
        redis.hset(k, f, v);
        assertEquals(0L, (long)redis.hdel(k, f1));
        assertEquals(0L, (long)redis.hdel(k, f2, f1));
    }

    @Test public void hdelShouldReturnOneWhenDeletingASingleField() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.hset(k, f, v);
        assertEquals(1L, (long)redis.hdel(k, f));
        assertEquals(0, redis.hkeys(k).size());
    }

    @Test public void hdelShouldReturnTheDeletedCountWhenDeletingMultipleFields() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f1 = "f1", f2 = "f2", f3 = "f3";
        redis.hset(k, f1, v);
        redis.hset(k, f2, v);
        redis.hset(k, f3, v);
        assertEquals(2L, (long)redis.hdel(k, f1, f2));
        assertEquals(1, redis.hkeys(k).size());
        redis.hset(k, f1, v);
        redis.hset(k, f2, v);
        assertEquals(3L, (long)redis.hdel(k, f1, f2, f3));
        assertEquals(0, redis.hkeys(k).size());
    }

    @Test public void hexistsShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hexists(k, f);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hexistsShouldReturnZeroIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(false, redis.hexists(k, f));
    }

    @Test public void hexistsShouldReturnZeroIfFieldDoesNotExistInKey() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f1 = "f1", f2 = "f2";
        redis.hset(k, f1, v);
        assertEquals(false, redis.hexists(k, f2));
    }

    @Test public void hexistsShouldReturnOneIfFieldExistsInKey() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f1 = "f1", f2 = "f2";
        redis.hset(k, f1, v);
        assertEquals(true, redis.hexists(k, f1));
        redis.hset(k, f2, v);
        assertEquals(true, redis.hexists(k, f2));
    }

    @Test public void hgetShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hget(k, f);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hgetShouldReturnNothingIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(null, redis.hget(k, f));
    }

    @Test public void hgetShouldReturnNothingIfFieldIsNotInKey() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field", f1 = "f1";
        redis.hset(k, f, v);
        assertEquals(null, redis.hget(k, f1));
    }

    @Test public void hgetShouldReturnTheFieldValue() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.hset(k, f, v);
        assertEquals(v, redis.hget(k, f));
    }

    @Test public void hgetallShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hgetall(k);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hgetallShouldReturnEmptyHashIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(0, redis.hgetall(k).size());
    }

    @Test public void hgetallShouldReturnAllTheKeysAndValuesInTheHash() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        String f1 = "f1", f2 = "f2", f3 = "f3";
        redis.hmset(k, f1, v1, f2, v2, f3, v3);
        Map<String, String> hgetall = redis.hgetall(k);
        assertEquals(3, hgetall.size());
        assertEquals(v1, hgetall.get(f1));
        assertEquals(v2, hgetall.get(f2));
        assertEquals(v3, hgetall.get(f3));
    }

    @Test public void hincrbyShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hincrby(k, f, 1L);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hincrbyShouldSetTheKeyAndFieldIfNeitherExistToTheIncrement() throws WrongTypeException, NotIntegerHashException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(1L, (long)redis.hincrby(k, f, 1L));
        assertEquals(1L, (long)Long.valueOf(redis.hget(k, f)));
        redis.del(k);
        assertEquals(-4L, (long)redis.hincrby(k, f, -4L));
        assertEquals(-4L, (long)Long.valueOf(redis.hget(k, f)));
    }

    @Test public void hincrbyShouldThrowAnErrorIfFieldIsNotAnInteger() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2";
        String v1 = "Five", v2 = "Yo Momma";
        redis.hmset(k, f1, v1, f2, v2);
        try {
            redis.hincrby(k, f1, 1L);
        }
        catch (NotIntegerHashException nihe) {
            assertEquals(true, true);
        }
        catch (Exception e) {
            assertEquals(false, true);
        }
        assertEquals(v1, redis.hget(k, f1));
        try {
            redis.hincrby(k, f2, -4L);
        }
        catch (NotIntegerHashException nihe) {
            assertEquals(v2, redis.hget(k, f2));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hincrbyShouldIncrTheValueAtFieldByTheIncrement() throws WrongTypeException, NotIntegerHashException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f = "f";
        Long v = 123L;
        redis.hset(k, f, String.valueOf(v));
        assertEquals(v + 2L, (long)redis.hincrby(k, f, 2L));
        assertEquals(v + 2L, (long)Long.valueOf(redis.hget(k, f)));
        assertEquals(v - 2L, (long)redis.hincrby(k, f, -4L));
        assertEquals(v - 2L, (long)Long.valueOf(redis.hget(k, f)));
    }

    @Test public void hincrbyfloatShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hincrbyfloat(k, f, 1.1d);
        }
        catch (WrongTypeException wte) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hincrbyfloatShouldSetTheKeyAndFieldIfNeitherExistToTheIncrement() throws WrongTypeException, NotFloatHashException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals("1.1", redis.hincrbyfloat(k, f, 1.1d));
        assertEquals("1.1", redis.hget(k, f));
    }

    @Test public void hincrbyfloatShouldThrowAnErrorIfFieldIsNotAFloat() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2";
        String v1 = "Five", v2 = "Yo Momma";
        redis.hmset(k, f1, v1, f2, v2);
        try {
            redis.hincrbyfloat(k, f1, 1.1d);
        }
        catch (NotFloatHashException nfhe) {
            assertEquals(v1, redis.hget(k, f1));
        }
        catch (Exception e) {
            assertEquals(false, true);
        }
        try {
            redis.hincrbyfloat(k, f2, -3.1415d);
        }
        catch (NotFloatHashException nfhe) {
            assertEquals(v2, redis.hget(k, f2));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hincrbyfloatShouldIncrTheValueAtFieldByTheIncrement() throws WrongTypeException, NotFloatHashException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f = "field";
        Double v = 123.456d;
        redis.hset(k, f, String.valueOf(v));
        assertEquals(v + 2.22d, Double.parseDouble(redis.hincrbyfloat(k, f, 2.22d)), 0.01d);
        assertEquals(v + 2.22d, Double.parseDouble(redis.hget(k, f)), 0.01d);
        assertEquals(v + 2.22d - 3.1415d, Double.parseDouble(redis.hincrbyfloat(k, f, -3.1415d)), 0.01d);
        assertEquals(v + 2.22d - 3.1415d, Double.parseDouble(redis.hget(k, f)), 0.01d);
    }

    @Test public void hkeysShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hkeys(k);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(true, false);
    }

    @Test public void hkeysShouldReturnAnEmptySetIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(0, redis.hkeys(k).size());
    }

    @Test public void hkeysShouldReturnAllTheKeysInAHash() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        String f1 = "f1", f2 = "f2", f3 = "f3";
        redis.hmset(k, f1, v1, f2, v2, f3, v3);
        Set<String> keys = redis.hkeys(k);
        assertEquals(3, keys.size());
        assertEquals(true, keys.contains(f1));
        assertEquals(true, keys.contains(f2));
        assertEquals(true, keys.contains(f3));
    }

    @Test public void hlenShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hlen(k);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hlenShoulReturnZeroIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(0L, (long)redis.hlen(k));
    }

    @Test public void hlenShouldReturnTheHashLength() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        String f1 = "f1", f2 = "f2", f3 = "f3";
        redis.hmset(k, f1, v1, f2, v2, f3, v3);
        assertEquals(3L, (long)redis.hlen(k));
    }

    @Test public void hmgetShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hmget(k, f);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
        }
        catch (Exception e) {
            assertEquals(false, true);
        }
        try {
            redis.hmget(k, f ,f ,f);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hmgetShouldReturnEmptyListIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(2, redis.hmget(k, f, f).size());
    }

    @Test public void hmgetShouldTheFieldsInTheHashAndNilsWhenAFieldIsNotInTheHash() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2", f3 = "f3";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        redis.hmset(k, f1, v1, f2, v2, f3, v3);
        List<String> get = redis.hmget(k, f1, f2, f3);
        assertEquals(3, get.size());
        get = redis.hmget(k, f1, f2, f3, f2, "na", f2, "na");
        assertEquals(7, get.size());
        assertEquals(redis.hget(k, f1), get.get(0));
        assertEquals(redis.hget(k, f2), get.get(1));
        assertEquals(redis.hget(k, f3), get.get(2));
        assertEquals(redis.hget(k, f2), get.get(3));
        assertEquals(null, get.get(4));
        assertEquals(redis.hget(k, f2), get.get(5));
        assertEquals(null, get.get(6));
    }

    @Test public void hmsetShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hmset(k, f, v, f, v);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hmsetShouldThrowAnErrorIfArgsAreBad() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        try {
            redis.hmset(k, f, v, f);
        }
        catch (ArgException ae) {
            assertEquals(true, true);
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hmsetShouldSetNewFieldsInTheHash() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2", f3 = "f3", f4 = "f4", f5 = "f5";
        String v =  "v", v1 = "v1";
        assertEquals("OK", redis.hmset(k, f1, v, f2, v));
        assertEquals(2L, (long)redis.hlen(k));
        assertEquals(v, redis.hget(k, f1));
        assertEquals(v, redis.hget(k, f2));
        assertEquals("OK", redis.hmset(k, f3, v, f4, v, f5, v, f1, v1));
        assertEquals(5L, (long)redis.hlen(k));
        assertEquals(v, redis.hget(k, f3));
        assertEquals(v, redis.hget(k, f4));
        assertEquals(v, redis.hget(k, f5));
        assertEquals(v1, redis.hget(k, f1));
    }

    @Test public void hsetShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hset(k, f, v);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hsetShouldSetANewFiledInAHashAndReturnOne() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2";
        String v = "v";
        assertEquals(true, redis.hset(k, f1, v));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v, redis.hget(k, f1));
        assertEquals(true, redis.hset(k, f2, v));
        assertEquals(2L, (long)redis.hlen(k));
        assertEquals(v, redis.hget(k, f2));
    }

    @Test public void hsetShouldUpdateAnExistingFieldInAHashAndReturnZero() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f = "f";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        assertEquals(true, redis.hset(k, f, v1));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v1, redis.hget(k, f));
        assertEquals(false, redis.hset(k, f, v2));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v2, redis.hget(k, f));
        assertEquals(false, redis.hset(k, f, v3));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v3, redis.hget(k, f));
    }

    @Test public void hsetnxShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f = "field";
        String v = "value";
        redis.set(k, v);
        try {
            redis.hsetnx(k, f, v);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hsetnxShouldSetANewFieldInAHashAndReturnOne() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2";
        String v = "v";
        assertEquals(true, redis.hsetnx(k, f1, v));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v, redis.hget(k, f1));
        assertEquals(true, redis.hsetnx(k, f2, v));
        assertEquals(2L, (long)redis.hlen(k));
        assertEquals(v, redis.hget(k, f2));
    }

    @Test public void hsetnxShouldNotUpdateAnExistingFieldAndReturnZero() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f = "f";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        assertEquals(true, redis.hsetnx(k, f, v1));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v1, redis.hget(k, f));
        assertEquals(false, redis.hsetnx(k, f, v2));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v1, redis.hget(k, f));
        assertEquals(false, redis.hsetnx(k, f, v3));
        assertEquals(1L, (long)redis.hlen(k));
        assertEquals(v1, redis.hget(k, f));
    }

    @Test public void hstrlenShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hstrlen(k, f);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hstrlenShouldReturnZeroForKeyOrFieldThatDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2";
        String v1 = "v1";
        assertEquals(0L, (long)redis.hstrlen(k, f1));
        redis.hset(k, f1, v1);
        assertEquals(0L, (long)redis.hstrlen(k, f2));
    }

    @Test public void hstrlenShouldReturnTheLengthOfTheStringAtField() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2";
        String v1 = "v1", v2 = "123";
        redis.hmset(k, f1, v1, f2, v2);
        assertEquals((long)v1.length(), (long)redis.hstrlen(k, f1));
        assertEquals((long)v2.length(), (long)redis.hstrlen(k, f2));
    }

    @Test public void hvalsShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        redis.set(k, v);
        try {
            redis.hvals(k);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hvalsShouldReturnAnEmptyListIfKeyDoesNotExist() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        String f = "field";
        assertEquals(0, redis.hvals(k).size());
    }

    @Test public void hvalsShouldReturnAllTheValuesInAHash() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2", f3 = "f3";
        String v1 = "v1", v2 = "v2", v3 = "v3";
        redis.hmset(k, f1, v1, f2, v2, f3, v3);
        List<String> vals = redis.hvals(k);
        assertEquals(3, vals.size());
        assertEquals(true, vals.contains(v1));
        assertEquals(true, vals.contains(v2));
        assertEquals(true, vals.contains(v3));
    }

    @Test public void hscanShouldThrowAnErrorIfKeyIsNotAHash() throws WrongTypeException, SyntaxErrorException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String v = "value";
        redis.set(k, v);
        try {
            redis.hscan(k, 0L);
        }
        catch (WrongTypeException wte) {
            assertEquals(v, redis.get(k));
            return;
        }
        catch (Exception e) {
        }
        assertEquals(false, true);
    }

    @Test public void hscanShouldScanThroughASmallHashAndReturnEveryFieldAndValue() throws WrongTypeException, ArgException {
        RedisMock redis = new RedisMock();
        String k = "key";
        String f1 = "f1", f2 = "f2", f3 = "f3", f4 = "f4";
        String v1 = "v1", v2 = "v2", v3 = "v3", v4 = "v4";
        redis.hmset(k, f1, v1, f2, v2, f3, v3);
        ScanResult<Map<String, String>> scan = redis.hscan(k, 0L);
        assertEquals(3L, (long)scan.cursor);
        assertEquals(3, scan.results.size());
        assertEquals(redis.hget(k, f1), scan.results.get(f1));
        assertEquals(redis.hget(k, f2), scan.results.get(f2));
        assertEquals(redis.hget(k, f3), scan.results.get(f3));
    }

    @Test public void hscanShouldScanThroughALargeSetWithCursoring() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        Map<String, String> hash = new HashMap<String, String>();
        for (int idx = 0; idx < 62; ++idx) {
            hash.put(String.valueOf(idx), String.valueOf(idx));
        }
        for (String key : hash.keySet()) {
            redis.hset(k, key, hash.get(key));
        }
        ScanResult<Map<String, String>> scan = new ScanResult<Map<String, String>>();
        Map<String, String> scanned = new HashMap<String, String>();
        while (true) {
            scan = redis.hscan(k, scan.cursor);
            if (scan.results.size() == 0) {
                break;
            }
            for (String key : scan.results.keySet()) {
                scanned.put(key, scan.results.get(key));
            }
        }
        assertEquals(hash.size(), scanned.size());
        for (String key : scanned.keySet()) {
            assertEquals(hash.get(key), scanned.get(key));
        }
        scan = redis.hscan(k, scan.cursor);
        assertEquals(0, scan.results.size());
    }

    @Test public void hscanShouldScanThroughALargeSetWithCursoringAndACount() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        Map<String, String> hash = new HashMap<String, String>();
        for (int idx = 0; idx < 62; ++idx) {
            hash.put(String.valueOf(idx), String.valueOf(idx));
        }
        for (String key : hash.keySet()) {
            redis.hset(k, key, hash.get(key));
        }
        ScanResult<Map<String, String>> scan = new ScanResult<Map<String, String>>();
        Map<String, String> scanned = new HashMap<String, String>();
        Long count = 5L;
        while (true) {
            scan = redis.hscan(k, scan.cursor, "count", String.valueOf(count));
            if (scan.results.size() == 0) {
                break;
            }
            for (String key : scan.results.keySet()) {
                scanned.put(key, scan.results.get(key));
            }
        }
        assertEquals(hash.size(), scanned.size());
        for (String key : scanned.keySet()) {
            assertEquals(hash.get(key), scanned.get(key));
        }
        scan = redis.hscan(k, scan.cursor, "count", String.valueOf(count));
        assertEquals(0, scan.results.size());
    }

    @Test public void hscanShouldScanThroughALargeSetWithCursoringAndAMatch() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        Map<String, String> hash = new HashMap<String, String>();
        for (int idx = 0; idx < 62; ++idx) {
            hash.put(String.valueOf(idx), String.valueOf(idx));
        }
        for (String key : hash.keySet()) {
            redis.hset(k, key, hash.get(key));
        }
        ScanResult<Map<String, String>> scan = new ScanResult<Map<String, String>>();
        Map<String, String> scanned = new HashMap<String, String>();
        String match = "[0-9]"; // All single digit #s.
        while (true) {
            scan = redis.hscan(k, scan.cursor, "match", match);
            if (scan.results.size() == 0) {
                break;
            }
            for (String key : scan.results.keySet()) {
                scanned.put(key, scan.results.get(key));
            }
        }
        assertEquals(10, scanned.size());
        for (String key : scanned.keySet()) {
            assertEquals(hash.get(key), scanned.get(key));
        }
        scan = redis.hscan(k, scan.cursor, "match", match);
        assertEquals(0, scan.results.size());
    }

    @Test public void hscanShouldScanThroughALargeSetWithCursoringACountAndAMatch() throws WrongTypeException {
        RedisMock redis = new RedisMock();
        String k = "key";
        Map<String, String> hash = new HashMap<String, String>();
        for (int idx = 0; idx < 62; ++idx) {
            hash.put(String.valueOf(idx), String.valueOf(idx));
        }
        for (String key : hash.keySet()) {
            redis.hset(k, key, hash.get(key));
        }
        ScanResult<Map<String, String>> scan = new ScanResult<Map<String, String>>();
        Map<String, String> scanned = new HashMap<String, String>();
        Long count = 5L;
        String match = "[0-9]"; // All single digit #s.
        while (true) {
            scan = redis.hscan(k, scan.cursor, "count", String.valueOf(count), "match", match);
            if (scan.results.size() == 0) {
                break;
            }
            for (String key : scan.results.keySet()) {
                scanned.put(key, scan.results.get(key));
            }
        }
        assertEquals(10, scanned.size());
        for (String key : scanned.keySet()) {
            assertEquals(hash.get(key), scanned.get(key));
        }
        scan = redis.hscan(k, scan.cursor, "match", match, "count", String.valueOf(count));
        assertEquals(0, scan.results.size());
    }

}


text:
import { initActionIgniteRunner } from "./infra/ignite_runner"
import { initActionStatePubSub } from "./infra/state_pub_sub"
import { initActionTerminateRunner } from "./infra/terminate_runner"

import {
    ApplicationActionIgniteHook,
    ApplicationActionIgniteRunner,
    ApplicationActionTerminateHook,
    ApplicationActionTerminateRunner,
} from "./infra"

import { ApplicationActionStateSubscriber, ApplicationStateAction } from "./action"

export abstract class ApplicationAbstractStateAction<S> implements ApplicationStateAction<S> {
    abstract readonly initialState: S

    readonly subscriber: ApplicationActionStateSubscriber<S>

    // this.material.doSomething(this.post) できるようにプロパティとして提供
    readonly post: Post<S>

    readonly igniteRunner: ApplicationActionIgniteRunner<S>
    readonly terminateRunner: ApplicationActionTerminateRunner = initActionTerminateRunner()

    constructor(hook: ApplicationActionIgniteHook<S> = async () => this.initialState) {
        const { pub, sub } = initActionStatePubSub<S>()
        this.subscriber = sub
        this.post = (state: S) => pub.post(state)

        this.igniteRunner = initActionIgniteRunner(hook)
        this.terminateHook(() => {
            pub.terminate()
        })
    }

    terminateHook(hook: ApplicationActionTerminateHook): void {
        this.terminateRunner.register(hook)
    }

    ignite(): Promise<S> {
        return new Promise((resolve) => {
            // すべての subscriber が登録された後で ignite するための setTimeout
            setTimeout(() => resolve(this.igniteRunner.ignite()))
        })
    }
    terminate(): void {
        this.terminateRunner.terminate()
    }
}

interface Post<S> {
    (state: S): S
}

redpajama_set_name: RedPajamaGithub


text:
package edu.uci.ics.hyracks.dataflow.std.structures;

public interface IResetable<T> {
    void reset(T other);
}


text:
#ifndef LL_WRITABLE_GRAPH_H_
#define LL_WRITABLE_GRAPH_H_

#include <sys/mman.h>
#include <sys/stat.h>

#include <fcntl.h>
#include <strings.h>
#include <unistd.h>

#include <map>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "llama/ll_common.h"
#include "llama/ll_mlcsr_graph.h"
#include "llama/ll_writable_array.h"
#include "llama/ll_writable_elements.h"

//==========================================================================//
// Class: ll_writable_graph                                                 //
//==========================================================================//

#ifdef LL_TX

/// The global thread-local transaction timestamp (is this a good idea?)
__thread long g_tx_timestamp;

/// Did this thread do any writes?
__thread bool g_tx_write;

/// The global transaction timestamp counter
std::atomic<long> g_last_timestamp(0);

/// The total number of active transactions
std::atomic<int> g_active_transactions(0);

#ifdef LL_TIMESTAMPS
#define LL_TX_TIMESTAMP		g_tx_timestamp
#else
#define LL_TX_TIMESTAMP		0
#endif

#else
#define LL_TX_TIMESTAMP		0
#endif

/**
 * The writable graph
 *
 * @author Peter Macko
 */
class ll_writable_graph {

	typedef struct {
		std::vector<edge_t> an_deleted_edges;
	} affected_node_by_edge_deletion_t;

public:

	/**
	 * Create an instance of ll_writable_graph
	 *
	 * @param database the database context
	 * @param storage the persistence context
	 * @param max_nodes maximum number of nodes
	 */
	ll_writable_graph(ll_database* database,
			IF_LL_PERSISTENCE(ll_persistent_storage* storage,)
			size_t max_nodes)

		: _ro_graph(database IF_LL_PERSISTENCE(, storage)),
		  _vertices(max_nodes),
		  _deletions_adapter_out(*this),
		  _deletions_adapter_in(*this)
	{
		_newNodes.store(0);
		_delNodes.store(0);
		_newEdges.store(0);
		_delNewEdges.store(0);
		_delFrozenEdges.store(0);

		_new_node_lock = 0;
		_deletions_out_lock = 0;
		_deletions_in_lock = 0;
		_property_lock = 0;

		_ro_graph.set_deletion_checkers(&_deletions_adapter_out,
				&_deletions_adapter_in);

		_next_new_node_id = _ro_graph.max_nodes();

#ifdef LL_WRITABLE_USE_MEMORY_POOL
		if (__w_pool.chunk_size() > ((1ul << LL_MEM_POOL_ALIGN_BITS) << LL_W_MEM_POOL_MAX_OFFSET_BITS)) {
			LL_E_PRINT("__w_pool.chunk_size() is too large\n");
			abort();
		}
#endif
	}

	/**
	 * Destroy the instance of this class
	 */
	virtual ~ll_writable_graph(void) {

#ifdef LL_WRITABLE_USE_MEMORY_POOL
		ll_free_w_pool();
#else
		delete_free_w_nodes();
		delete_free_w_edges();
#endif
	}

#ifdef LL_MIN_LEVEL
	/**
	 * Set the minimum level to consider
	 *
	 * @param m the minimum level
	 */
	void set_min_level(edge_t m) {

		_ro_graph.set_min_level(m);
	}
#endif

	/**
	 * Begin a transaction
	 *
	 * @return the new transaction ID
	 */
	long tx_begin() {
#ifdef LL_TX
		g_active_transactions.fetch_add(1);
		g_tx_timestamp = g_last_timestamp.fetch_add(1) + 1;
		g_tx_write = false;
		return g_tx_timestamp;
#else
		return 0;
#endif
	}

	/**
	 * Commit the transaction
	 */
	void tx_commit() {
#ifdef LL_TX
		g_tx_timestamp = 0;
		int n = g_active_transactions.fetch_add(-1);
		assert(n > 0); (void) n;
#endif
	}

	/**
	 * Abort the transaction
	 */
	void tx_abort() {
#ifdef LL_TX
		g_tx_timestamp = 0;
		int n = g_active_transactions.fetch_add(-1);
		assert(n > 0); (void) n;
#endif

		// TODO What to do now?

		abort();
	}

	/**
	 * Return the number of nodes
	 *
	 * @return the number of nodes
	 */
    node_t max_nodes() {
		return _next_new_node_id;
    }

	/**
	 * Return the number of edges within the given level
	 *
	 * @param level the level number
	 * @return the number of edges
	 */
    edge_t max_edges(int level) {
		if (level >= (int) _ro_graph.num_levels())
			return _newEdges;
		else
			return _ro_graph.max_edges(level);
    }

	/**
	 * Return the number of levels
	 *
	 * @return the number of levels
	 */
    inline size_t num_levels() {
        return _ro_graph.num_levels() + 1;
    }

	/**
	 * Determine whether we have up-to-date reverse edges
	 *
	 * @return true if yes and up-to-date
	 */
	bool has_reverse_edges() {
		return _ro_graph.has_reverse_edges();
	}

	/**
	 * Pick a random node
	 *
	 * @return a random node
	 */
    node_t pick_random_node() {
        while (true) {
			node_t n = ll_rand64_positive() % max_nodes();
			if (node_exists(n)) return n;
		}
    }

	/**
	 * Get the read-only graph for the analytics
	 *
	 * @return the read-only graph
	 */
	ll_mlcsr_ro_graph& ro_graph(void) {
		return _ro_graph;
	}

	/**
	 * A hook for when a new level was added to the read-only graph
	 */
	void callback_ro_changed(void) {

		ll_spinlock_acquire(&_new_node_lock);
		_next_new_node_id = _ro_graph.max_nodes();
		ll_spinlock_release(&_new_node_lock);
	}

	/**
	 * Determine if the given node exists in the latest level
	 *
	 * @param node the node
	 * @return true if it exists
	 */
	inline bool node_exists(node_t node) {

		w_node* r = (w_node*) _vertices.get(node);
		if (r != NULL) return true;

		return _ro_graph.node_exists(node);
	}

	/**
	 * Add a node
	 *
	 * @return the node ID, or NIL_NODE if there is no more space in the vertex map
	 */
	node_t add_node() {

		ll_spinlock_acquire(&_new_node_lock);

		if (_next_new_node_id + 1 >= (node_t) _vertices.size()) {
			ll_spinlock_release(&_new_node_lock);
			return LL_NIL_NODE;
		}

#ifdef LL_TX
		g_tx_write = true;
#endif

		node_t n = _next_new_node_id++;
		assert(!node_exists(n));

		// TODO We just want to allocate - or do we need to
		// do that spinlock thing? Maybe it's not necessary.
		w_node* r = (w_node*) _vertices.get_or_allocate(n);
		(void) r;

#ifdef LL_TIMESTAMPS
		r->wn_timestamp_creation = LL_TX_TIMESTAMP;
#endif

		_newNodes++;
		ll_spinlock_release(&_new_node_lock);

		return n;
	}

	/**
	 * Add a node with the given ID
	 *
	 * @param id the new node ID
	 * @return true if it went okay; false if we failed
	 */
	bool add_node(node_t id) {

		ll_spinlock_acquire(&_new_node_lock);

		if (id >= (node_t) _vertices.size()) {
			ll_spinlock_release(&_new_node_lock);
			return false;
		}

#ifdef LL_TX
		g_tx_write = true;
#endif

		if (id > _next_new_node_id) _next_new_node_id = id;
		if (node_exists(id)) {
			ll_spinlock_release(&_new_node_lock);
			return false;
		}

		// TODO We just want to allocate - or do we need to
		// do that spinlock thing? Maybe it's not necessary.
		w_node* r = (w_node*) _vertices.get_or_allocate(id);
		(void) r;

#ifdef LL_TIMESTAMPS
		r->wn_timestamp_creation = LL_TX_TIMESTAMP;
#endif

		_newNodes++;	// TODO Make checkpointing to work
		ll_spinlock_release(&_new_node_lock);

		return true;
	}

	/**
	 * Delete a node
	 *
	 * @return node the node
	 */
	void delete_node(node_t node) {

#ifdef LL_DELETIONS
		w_node* p_node = lock_node(node);

		// Check if the node is already deleted

#ifdef LL_TIMESTAMPS
		long t = LL_TX_TIMESTAMP;
		if (t < p_node->wn_timestamp_creation
				|| t >= p_node->wn_timestamp_deletion) {
			release_node(p_node);
			return;
		}
#else
		if (!p_node->exists()) {
			release_node(p_node);
			return;
		}
#endif

#ifdef D_DEBUG_NODE
		if (node == D_DEBUG_NODE) {
			fprintf(stderr, "%p: delete_node %ld: %ld new out-edges, "
					"%ld new in-edges, %s RO graph\n", this, node,
					p_node->wn_out_edges.size(),
					p_node->wn_in_edges.size(),
					_ro_graph.node_exists(node) ? "in" : "not in");
		}
#endif

		// Mark the transaction as write

#ifdef LL_TX
		g_tx_write = true;
#endif

		// Update the counter

		if (p_node->exists()) {
			_delNodes++;
		}

		// Mark the node as deleted

#ifdef LL_TIMESTAMPS
		p_node->wn_timestamp_deletion = LL_TX_TIMESTAMP;
#else
		p_node->wn_deleted = true;
#endif

		if (_ro_graph.node_exists(node)) {

			// Delete the frozen out-edges

#ifdef D_DEBUG_NODE
			if (node == D_DEBUG_NODE)
				fprintf(stderr, "%p: delete_node %ld: frozen out-edges\n", this, node);
#endif
			ll_edge_iterator iter;
			_ro_graph.out_iter_begin(iter, node);
			FOREACH_OUTEDGE_ITER(edge, _ro_graph, iter) {
				delete_edge(node, edge);
			}

			// Delete the frozen in-edges

#ifdef D_DEBUG_NODE
			if (node == D_DEBUG_NODE)
				fprintf(stderr, "%p: delete_node %ld: frozen in-edges\n", this, node);
#endif
			_ro_graph.in_iter_begin(iter, node);
			FOREACH_INEDGE_ITER(edge, _ro_graph, iter) {
				delete_edge(iter.last_node, edge);
			}
		}

		// Delete the new out-edges

		for (size_t i = 0; i < p_node->wn_out_edges.size(); i++) {
			w_edge* e = p_node->wn_out_edges[i];
			if (e->exists()) _delNewEdges++;

			w_node* p_target = e->we_target == node
				? p_node : try_lock_node(e->we_target);
			if (p_target == NULL) {
				release_node(p_node);
				lock_nodes(node, e->we_target, p_node, p_target);
			}

#ifdef D_DEBUG_NODE
			if (node == D_DEBUG_NODE || e->we_target == D_DEBUG_NODE)
				fprintf(stderr, "%p: delete_node %ld: new out-edge (%p) %ld --> %ld\n",
						this, node, e, node, e->we_target);
#endif

#ifdef LL_TIMESTAMPS
			if (t < e->we_timestamp_deletion) {
				e->we_timestamp_deletion = t;
				if (t > p_target->wn_timestamp_update) p_target->wn_timestamp_update = t;
				p_target->wn_in_edges_delta--;	// TODO What kind of condition do I need for this?
			}
#else
			if (e->exists()) {
				e->we_deleted = true;
				assert(p_target->wn_in_edges_delta > 0);
				p_target->wn_in_edges_delta--;
			}
#endif

			if (p_node != p_target) release_node(p_target);
		}

		// Delete the new in-edges

		for (size_t i = 0; i < p_node->wn_in_edges.size(); i++) {
			w_edge* e = p_node->wn_in_edges[i];
			if (e->we_source == node) continue;
			if (e->exists()) _delNewEdges++;

			w_node* p_source = try_lock_node(e->we_source);
			if (p_source == NULL) {
				release_node(p_node);
				lock_nodes(node, e->we_source, p_node, p_source);
			}

#ifdef D_DEBUG_NODE
			if (node == D_DEBUG_NODE || e->we_source == D_DEBUG_NODE)
				fprintf(stderr, "%p: delete_node %ld: new in-edge (%p) %ld --> %ld\n",
						this, node, e, e->we_source, node);
#endif

#ifdef LL_TIMESTAMPS
			if (t < e->we_timestamp_deletion) {
				e->we_timestamp_deletion = t;
				if (t > p_source->wn_timestamp_update) p_source->wn_timestamp_update = t;
				p_source->wn_out_edges_delta--;
			}
#else
			if (e->exists()) {
				e->we_deleted = true;
				assert(p_source->wn_out_edges_delta > 0);
				p_source->wn_out_edges_delta--;
			}
#endif

			release_node(p_source);
		}

		// Update the counters

		p_node->wn_out_edges_delta = 0;
		p_node->wn_in_edges_delta = 0;

		// Cleanup

		release_node(p_node);
#endif
	}

protected:

	/**
	 * Add an edge
	 *
	 * @param source the source node
	 * @param target the destination node
	 * @param p_source the locked source node
	 * @param p_target the locked destination node
	 * @return the edge ID
	 */
	edge_t add_edge(node_t source, node_t target, w_node* p_source, w_node* p_target) {

		LL_D_NODE2_PRINT(source, target, "Add %ld --> %ld\n", source, target);

		w_edge_allocator _allocator;
#ifdef LL_WRITABLE_USE_MEMORY_POOL
		size_t we_chunk, we_offset;
		w_edge* we = _allocator(&we_chunk, &we_offset);
		we->we_public_id = LL_EDGE_CREATE(LL_WRITABLE_LEVEL,
				(we_chunk << LL_W_MEM_POOL_MAX_OFFSET_BITS)
				| (we_offset >> LL_MEM_POOL_ALIGN_BITS));
#else
		w_edge* we = _allocator();
		we->we_public_id = LL_EDGE_CREATE(LL_WRITABLE_LEVEL, (edge_t) (long) we);
#endif
		w_edge* p_edge = p_source->wn_out_edges.append(we);
		p_target->wn_in_edges.append(p_edge);

#ifndef LL_WRITABLE_USE_MEMORY_POOL
#ifdef LL_NODE32
#warning "LL_NODE32 is not good; please use LL_NODE64 instead!"
		if (((unsigned long) p_edge) >= (1ul << 28)) {
			fprintf(stderr, "\n\nFATAL: Edge pointer out of range %p "
					"-- use LL_NODE64\n", p_edge);
			abort();
		}
#endif
		// Huh, it would be great if we did not need this!
		if (((unsigned long) p_edge) >= (1ull << LL_BITS_INDEX)) {
			fprintf(stderr, "\n\nFATAL: Edge pointer out of range %p\n", p_edge);
			abort();
		}
#endif

#ifdef LL_TX
		g_tx_write = true;
#endif

		edge_t out_edge = we->we_public_id;
		assert(LL_EDGE_GET_WRITABLE(out_edge) == p_edge);

		p_edge->we_target = target;
		p_edge->we_source = source;

#ifdef LL_TIMESTAMPS
		long t = LL_TX_TIMESTAMP;

		p_edge->we_timestamp_creation = t;

		if (t > p_source->wn_timestamp_update) p_source->wn_timestamp_update = t;
		if (t > p_target->wn_timestamp_update) p_target->wn_timestamp_update = t;

		p_edge->we_timestamp_deletion = LONG_MAX;
#else
		p_edge->we_deleted = false;
#endif

		p_source->wn_out_edges_delta++;
		p_target->wn_in_edges_delta++;

		uint32_t id = _newEdges.fetch_add(1);
		p_edge->we_numerical_id = id;

		return out_edge;
	}

public:

	/**
	 * Add an edge
	 *
	 * @param source the source node
	 * @param target the destination node
	 * @return the edge ID
	 */
	edge_t add_edge(node_t source, node_t target) {

		edge_t out_edge;
		w_node* p_source;
		w_node* p_target;

		lock_nodes(source, target, p_source, p_target);
		out_edge = add_edge(source, target, p_source, p_target);
		release_nodes(p_source, p_target);

		return out_edge;
	}

	/**
	 * Add edge if it does not already exists. If the edge already exists,
	 * return its ID in place of the new edge ID.
	 *
	 * It requires that there is at most one existing edge that matches
	 *
	 * @param source the source node
	 * @param target the destination node
	 * @param out the output for the edge ID
	 * @return true if the edge was added; false if it it already exists
	 */
	bool add_edge_if_not_exists(node_t source, node_t target, edge_t* out) {

		edge_t e;

		if (_ro_graph.node_exists(source) && _ro_graph.node_exists(target)) {
			e = _ro_graph.find(source, target);
			if (e != LL_NIL_EDGE) {
				*out = e;
				return false;
			}
		}

		w_node* p_source;
		w_node* p_target;

		lock_nodes(source, target, p_source, p_target);

		ll_edge_iterator iter;
		this->out_iter_begin_within_level(iter, source);
		FOREACH_OUTEDGE_ITER_WITHIN_LEVEL(e, *this, iter) {
			if (iter.last_node == target) {
				*out = e;
				release_nodes(p_source, p_target);
				return false;
			}
		}

		e = add_edge(source, target, p_source, p_target);
		release_nodes(p_source, p_target);

		*out = e;
		return true;
	}

#ifdef LL_S_WEIGHTS_INSTEAD_OF_DUPLICATE_EDGES

	/**
	 * Add an edge for streaming applications with weights. If an edge already
	 * exists in the read-only graph, delete it, and recreate it with the
	 * incremented weight. If the edge already exists in the writable level,
	 * increment the weight.
	 *
	 * @param source the source node
	 * @param target the destination node
	 * @param out the output for the edge ID
	 * @return true if the edge was added; false if it it already exists
	 */
	bool add_edge_for_streaming_with_weights(node_t source, node_t target, edge_t* out) {

		LL_D_NODE2_PRINT(source, target, "Add for streaming: %ld --> %ld\n",
				source, target);

		ll_mlcsr_edge_property<uint32_t>* w = get_edge_weights_streaming();
		uint32_t ro_weight = 0;
		edge_t ro_edge = LL_NIL_EDGE;

		w_node* p_source;
		w_node* p_target;

		lock_nodes(source, target, p_source, p_target);

		ll_edge_iterator iter;
		this->out_iter_begin_within_level(iter, source);
		FOREACH_OUTEDGE_ITER_WITHIN_LEVEL(e, *this, iter) {
			if (iter.last_node == target) {

				w->add(e, 1);
				release_nodes(p_source, p_target);

				*out = e;

				LL_D_NODE2_PRINT(source, target,
						"Found duplicate of R/W edge %ld --> %ld\n",
						source, target);

				return false;
			}
		}

		if (_ro_graph.node_exists(source) && _ro_graph.node_exists(target)) {
			ro_edge = _ro_graph.find(source, target);
			if (ro_edge != LL_NIL_EDGE) {
				ro_weight = (*w)[ro_edge];
				LL_D_NODE2_PRINT(source, target,
						"Found duplicate of %lx, old weight = %u, "
						"old forward = %lx\n",
						ro_edge, ro_weight,
						_ro_graph.get_edge_forward_streaming()->get(ro_edge));
				assert(_ro_graph.get_edge_forward_streaming()->get(ro_edge) == 0);
				delete_edge(source, ro_edge);
			}
		}

		edge_t new_edge = add_edge(source, target, p_source, p_target);
		w->set(new_edge, ro_weight + 1);

		LL_EDGE_GET_WRITABLE(new_edge)->we_supersedes = ro_edge;

		release_nodes(p_source, p_target);
		*out = new_edge;
		return true;
	}

#endif

	/**
	 * Delete an edge
	 *
	 * @param source the source node
	 * @return edge the edge
	 */
	void delete_edge(node_t source, edge_t edge) {

#ifdef LL_DELETIONS

		// Needs edge sources

		w_node* p_source;
		w_node* p_target;

		long t = LL_TX_TIMESTAMP;
		(void) t;

		if (LL_EDGE_IS_WRITABLE(edge)) {

			w_edge* w = LL_EDGE_GET_WRITABLE(edge);

			node_t target = w->we_target;
			assert(source == w->we_source);
			//node_t source = w->we_source;

			lock_nodes(source, target, p_source, p_target);

			LL_D_NODE2_PRINT(source, target,
					"delete writable edge=%08lx %ld --> %ld",
					edge, source, target);

#ifdef LL_TX
			g_tx_write = true;
#endif

			// Delete the edge and update the timestamps

#ifdef LL_TIMESTAMPS
			if (t < w->we_timestamp_deletion) {
				w->we_timestamp_deletion = t;
				if (t > p_source->wn_timestamp_update) p_source->wn_timestamp_update = t;
				if (t > p_target->wn_timestamp_update) p_target->wn_timestamp_update = t;

				p_source->wn_out_edges_delta--;
				p_target->wn_in_edges_delta--;

				if (w->we_timestamp_deletion != LONG_MAX) {
					_delNewEdges++;
				}
			}
#else
			if (w->exists()) {
				p_source->wn_out_edges_delta--;
				p_target->wn_in_edges_delta--;
			}

			w->we_deleted = true;

			_delNewEdges++;
#endif

			// Finish

			release_nodes(p_source, p_target);
		}
		else {

			//node_t source = _ro_graph.edge_src(edge);
			assert(source == _ro_graph.in().value(_ro_graph.out_to_in(edge)));
			node_t target = _ro_graph.edge_dst(edge);

			LL_D_NODE2_PRINT(source, target,
					"delete frozen edge=%08lx, in_edge=%08lx %ld --> %ld",
					edge, _ro_graph.out_to_in(edge), source, target);

#ifdef LL_TIMESTAMPS

			// Lock / latch the data structures

			// TODO A finer granularity lock? The following are just intended to be latches
			// for the deletion maps data structures

			ll_spinlock_acquire(&_deletions_out_lock);
			ll_spinlock_acquire(&_deletions_in_lock);

			// Update the external deletion maps

#ifdef LL_TX
			g_tx_write = true;
#endif

			auto it = _deletions_out_map.find(edge);
			bool alreadyDeleted = false;
			if (it == _deletions_out_map.end()) {
				_deletions_out_map[edge] = t;
			}
			else {
				it->second = std::min(t, it->second);
				alreadyDeleted = true;
			}

			if (!alreadyDeleted) {
				_deletions_nodes_out[LL_D_STRIPE(source)][source]
					.an_deleted_edges.push_back(edge);
			}

			if (_ro_graph.has_reverse_edges()) {
				edge_t in_edge = _ro_graph.out_to_in(edge);
				it = _deletions_in_map.find(in_edge);
				if (it == _deletions_in_map.end()) {
					_deletions_in_map[in_edge] = t;
					alreadyDeleted = false;
				}
				else {
					it->second = std::min(t, it->second);
					alreadyDeleted = true;
				}

				if (!alreadyDeleted) {
					_deletions_nodes_in[LL_D_STRIPE(target)][target]
						.an_deleted_edges.push_back(in_edge);
				}
			}

			// TODO Update the timestamps at the nodes?

			// Update the max. level in the CSR

			if (_ro_graph.update_max_visible_level_lower_only(edge, LL_CHECK_EXT_DELETION)) {
#	ifdef D_DEBUG_NODE
				if (source == D_DEBUG_NODE || target == D_DEBUG_NODE) fprintf(stderr, " [ok]");
#	endif
				__sync_fetch_and_add(&writable_node(source)->wn_num_deleted_out_edges, 1);
				__sync_fetch_and_add(&writable_node(target)->wn_num_deleted_in_edges , 1);
				_delFrozenEdges++;
			}

			// Release locks

			ll_spinlock_release(&_deletions_in_lock);
			ll_spinlock_release(&_deletions_out_lock);

#else /* !LL_TIMESTAMPS */

			// Update the max. level in the CSR

			if (_ro_graph.update_max_visible_level_lower_only(edge, _ro_graph.num_levels())) {
#	ifdef D_DEBUG_NODE
				if (source == D_DEBUG_NODE || target == D_DEBUG_NODE) fprintf(stderr, " [ok]");
#	endif
				__sync_fetch_and_add(&writable_node(source)->wn_num_deleted_out_edges, 1);
				__sync_fetch_and_add(&writable_node(target)->wn_num_deleted_in_edges , 1);
				_delFrozenEdges++;		// already atomic
			}
#endif

#ifdef D_DEBUG_NODE
			if (source == D_DEBUG_NODE || target == D_DEBUG_NODE) fprintf(stderr, "\n");
#endif
		}

#endif
	}

	/**
	 * Get the destination of the edge
	 *
	 * @param e the edge
	 * @return the node
	 */
    node_t edge_dst(edge_t e) {
		if (LL_EDGE_IS_WRITABLE(e))
			return LL_EDGE_GET_WRITABLE(e)->we_target;
		else
			return _ro_graph.edge_dst(e);
    }

	/**
	 * Get the node out-degree
	 *
	 * @param node the node
	 * @return the out-degree
	 */
	size_t out_degree(node_t node) {

		w_node* r = (w_node*) _vertices.get(node);
		size_t d = 0;

		if (r != NULL) {

#ifdef LL_DELETIONS
#	ifdef LL_TIMESTAMPS
			long t = LL_TX_TIMESTAMP;
			if (t < r->wn_timestamp_creation
					|| t >= r->wn_timestamp_deletion) return 0;

			size_t n = r->wn_out_edges.size();
			for (size_t i = 0; i < n; i++) {
				const w_edge& e = r->wn_out_edges[i];
				if (t >= e.we_timestamp_creation
						&& t < e.we_timestamp_deletion) d++;
			}
#	else
			if (!r->exists()) return 0;
			d = r->wn_out_edges_delta;
#	endif
#else
			d = r->wn_out_edges.size();
#endif
#ifndef LL_TIMESTAMPS
			d -= r->wn_num_deleted_out_edges;
#endif
		}

#ifdef LL_CHECK_NODE_EXISTS_IN_RO
		d += _ro_graph.out_degree(node);
#else
		d += _ro_graph.node_exists(node) ? _ro_graph.out_degree(node) : 0;
#endif

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS

		// Having to take this spinlock is extremely slow - so let's try something else

retry:
		auto& h = _deletions_nodes_out[LL_D_STRIPE(node)];
		size_t size = h.size();
		__COMPILER_FENCE;
		auto it = h.find(node);
		if (it != h.end()) {
			auto& x = it->second;
			__COMPILER_FENCE;
			size_t size2 = h.size();
			if (size != size2) goto retry;

			auto& v = it->second.an_deleted_edges;
			long t = LL_TX_TIMESTAMP;
			for (size_t i = 0; i < v.size(); i++) {
				if (_deletions_out_map[v[i]] <= t) d--;
			}
		}

#endif
#endif

		return d;
	}

	/**
	 * Get the node in-degree
	 *
	 * @param node the node
	 * @return the in-degree
	 */
	size_t in_degree(node_t node) {

		w_node* r = (w_node*) _vertices.get(node);
		size_t d = 0;

		if (r != NULL) {

#ifdef LL_DELETIONS
#	ifdef LL_TIMESTAMPS
			long t = LL_TX_TIMESTAMP;
			if (t < r->wn_timestamp_creation
					|| t >= r->wn_timestamp_deletion) return 0;

			size_t n = r->wn_in_edges.size();
			for (size_t i = 0; i < n; i++) {
				const w_edge& e = r->wn_in_edges[i];
				if (t >= e.we_timestamp_creation
						&& t < e.we_timestamp_deletion) d++;
			}
#	else
			if (!r->exists()) return 0;
			d = r->wn_in_edges_delta;
#	endif
#else
			d = r->wn_in_edges.size();
#endif
#ifndef LL_TIMESTAMPS
			d -= r->wn_num_deleted_in_edges;
#endif
		}

#ifdef LL_CHECK_NODE_EXISTS_IN_RO
		d += _ro_graph.in_degree(node);
#else
		d += _ro_graph.node_exists(node) ? _ro_graph.in_degree(node) : 0;
#endif

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS

		// Having to take this spinlock is extremely slow - so let's try something else

retry:
		auto& h = _deletions_nodes_in[LL_D_STRIPE(node)];
		size_t size = h.size();
		__COMPILER_FENCE;
		auto it = h.find(node);
		if (it != h.end()) {
			auto& x = it->second;
			__COMPILER_FENCE;
			size_t size2 = h.size();
			if (size != size2) goto retry;

			auto& v = it->second.an_deleted_edges;
			long t = LL_TX_TIMESTAMP;
			for (size_t i = 0; i < v.size(); i++) {
				if (_deletions_in_map[v[i]] <= t) d--;
			}
		}
#endif
#endif

		return d;
	}

	/**
	 * Create iterator over all outgoing edges
	 *
	 * @param iter the iterator
	 * @param v the vertex
	 * @return the iterator
	 */
	void out_iter_begin(ll_edge_iterator& iter, node_t node) {

		w_node* r = (w_node*) _vertices.get(node);
		if (r == NULL) {
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
			if (!_ro_graph.node_exists(node)) {
				_ro_graph.out().iter_set_to_end(iter);
				LL_D_NODE_PRINT(node,
						"The node does not exist or have any edges\n");
				return;
			}
#endif
			_ro_graph.out_iter_begin(iter, node, _ro_graph.num_levels()-1,
					_ro_graph.num_levels());
			LL_D_NODE_PRINT(node, "[owner=%d, left=%ld]\n",
					(int) iter.owner, (long) iter.left);
			return;
		}

		// Check if the node is deleted

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
		long t = LL_TX_TIMESTAMP;
		if (t < r->wn_timestamp_creation
				|| t >= r->wn_timestamp_deletion) {
			_ro_graph.out().iter_set_to_end(iter);
			return;
		}
#else
		if (!r->exists()) {
			_ro_graph.out().iter_set_to_end(iter);
			return;
		}
#endif
#endif

		// Create the iterator struct

		iter.owner = LL_I_OWNER_WRITABLE;
		iter.ptr = r;
		iter.node = node;
		iter.left = r->wn_out_edges.size();

		if (iter.left == 0) {
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
			if (!_ro_graph.node_exists(node)) {
				_ro_graph.out().iter_set_to_end(iter);
				LL_D_NODE_PRINT(node,
						"The node does not exist or have any edges\n");
				return;
			}
#endif
			_ro_graph.out_iter_begin(iter, node, _ro_graph.num_levels()-1,
					_ro_graph.num_levels());
		}
		else {
			w_edge* e = ((w_node*) iter.ptr)->wn_out_edges[--iter.left];
			iter.edge = (long) e;
#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
			if (g_tx_timestamp < e->we_timestamp_creation
					|| g_tx_timestamp >= e->we_timestamp_deletion) {
				out_iter_next(iter);
			}
#else
			if (!e->exists()) {
				out_iter_next(iter);
			}
#endif
#endif
		}

		LL_D_NODE_PRINT(node, "[owner=%d, left=%ld]\n",
				(int) iter.owner, (long) iter.left);
	}

	/**
	 * Determine if there are any more items left
	 *
	 * @param iter the iterator
	 * @return true if there are more items
	 */
	ITERATOR_DECL bool out_iter_has_next(ll_edge_iterator& iter) {

		if (iter.owner != LL_I_OWNER_WRITABLE) {
			return _ro_graph.out_iter_has_next(iter);
		}

		return iter.edge != LL_NIL_EDGE;
	}

	/**
	 * Get the next item
	 *
	 * @param iter the iterator
	 * @return the next item, or LL_NIL_EDGE if none
	 */
	ITERATOR_DECL edge_t out_iter_next(ll_edge_iterator& iter) {

		if (iter.owner != LL_I_OWNER_WRITABLE) {
			return _ro_graph.out_iter_next(iter);
		}

		edge_t r = iter.edge;
		if (r == LL_NIL_EDGE) return LL_NIL_EDGE;

		iter.last_node = ((w_edge*) r)->we_target;

		w_edge* e;
		do {
			if (iter.left == 0)	{
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
				if (!_ro_graph.node_exists(iter.node)) {
					_ro_graph.out().iter_set_to_end(iter);
					break;
				}
#endif
				_ro_graph.out_iter_begin(iter, iter.node, _ro_graph.num_levels()-1, _ro_graph.num_levels());
				break;
			}

			assert(iter.left > 0);
			e = ((w_node*) iter.ptr)->wn_out_edges[--iter.left];
			iter.edge = (long) e;

#ifdef LL_DELETIONS
		}
#ifdef LL_TIMESTAMPS
		while (g_tx_timestamp < e->we_timestamp_creation
				|| g_tx_timestamp >= e->we_timestamp_deletion);
#else
		while (!e->exists());
#endif
#elif 0
		{
#else
			break;
		}
		while (true);
#endif

		return LL_W_EDGE_CREATE(r);
	}

	/**
	 * Start an iterator and get the next value immediately
	 *
	 * @param iter the iterator
	 * @param n the node
	 * @param level the level
	 * @param max_level the max level for deletions
	 * @return the next item, or LL_NIL_EDGE if none
	 */
	inline edge_t out_iter_begin_next(ll_edge_iterator& iter, node_t n,
			int level=-1, int max_level=-1) {
		this->out_iter_begin(iter, n);
		return this->out_iter_next(iter);
	}

	/**
	 * Finish the iterator
	 *
	 * @param iter the iterator
	 */
	inline void out_iter_end(ll_edge_iterator& iter) {
	}

	/**
	 * Create iterator over all outgoing edges within this level
	 *
	 * @param iter the iterator
	 * @param v the vertex
	 * @return the iterator
	 */
	void out_iter_begin_within_level(ll_edge_iterator& iter, node_t node) {

		w_node* r = (w_node*) _vertices.get(node);

		if (r == NULL) {
			iter.left = 0;
			iter.edge = LL_NIL_EDGE;
		}
		else {

			// Check if the node is deleted

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
			long t = LL_TX_TIMESTAMP;
			if (t < r->wn_timestamp_creation
					|| t >= r->wn_timestamp_deletion) {
				_ro_graph.out().iter_set_to_end(iter);
				return;
			}
#else
			if (!r->exists()) {
				_ro_graph.out().iter_set_to_end(iter);
				return;
			}
#endif
#endif

			// Create the iterator struct

			iter.owner = LL_I_OWNER_WRITABLE;
			iter.ptr = r;
			iter.node = node;
			iter.left = r->wn_out_edges.size();

			if (iter.left == 0) {
				iter.edge = LL_NIL_EDGE;
			}
			else {
				w_edge* e = ((w_node*) iter.ptr)->wn_out_edges[--iter.left];
				iter.edge = (long) e;

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
				if (g_tx_timestamp < e->we_timestamp_creation
						|| g_tx_timestamp >= e->we_timestamp_deletion) {
					out_iter_next_within_level(iter);
				}
#else
				if (!e->exists()) {
					out_iter_next_within_level(iter);
				}
#endif
#endif
			}
		}
	}

	/**
	 * Determine if there are any more items left within this level
	 *
	 * @param iter the iterator
	 * @return true if there are more items
	 */
	ITERATOR_DECL bool out_iter_has_next_within_level(ll_edge_iterator& iter) {
		return iter.edge != LL_NIL_EDGE;
	}

	/**
	 * Get the next item, but only within this level
	 *
	 * @param iter the iterator
	 * @return the next item, or LL_NIL_EDGE if none
	 */
	ITERATOR_DECL edge_t out_iter_next_within_level(ll_edge_iterator& iter) {

		edge_t r = iter.edge;
		if (r == LL_NIL_EDGE) return LL_NIL_EDGE;

		iter.last_node = ((w_edge*) r)->we_target;

		w_edge* e;
		do {
			if (iter.left == 0)	{
				iter.edge = LL_NIL_EDGE;
				break;
			}

			assert(iter.left > 0);
			e = ((w_node*) iter.ptr)->wn_out_edges[--iter.left];
			iter.edge = (long) e;

#ifdef LL_DELETIONS
		}
#ifdef LL_TIMESTAMPS
		while (g_tx_timestamp < e->we_timestamp_creation
				|| g_tx_timestamp >= e->we_timestamp_deletion);
#else
		while (!e->exists());
#endif
#elif 0
		{
#else
			break;
		}
		while (true);
#endif

		return LL_W_EDGE_CREATE(r);
	}

	/**
	 * Create iterator over all incoming edges
	 *
	 * @param iter the iterator
	 * @param v the vertex
	 * @return the iterator
	 */
	void in_iter_begin_fast(ll_edge_iterator& iter, node_t node) {

		w_node* r = (w_node*) _vertices.get(node);
		if (r == NULL) {
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
			if (!_ro_graph.node_exists(node)) {
				_ro_graph.in().iter_set_to_end(iter);
				return;
			}
#endif
			_ro_graph.in_iter_begin_fast(iter, node);
			return;
		}

		// Check if the node is deleted

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
		long t = LL_TX_TIMESTAMP;
		if (t < r->wn_timestamp_creation
				|| t >= r->wn_timestamp_deletion) {
			_ro_graph.in().iter_set_to_end(iter);
			return;
		}
#else
		if (!r->exists()) {
			_ro_graph.in().iter_set_to_end(iter);
			return;
		}
#endif
#endif

		// Create the iterator struct

		iter.owner = LL_I_OWNER_WRITABLE;
		iter.ptr = r;
		iter.node = node;
		iter.left = r->wn_in_edges.size();

		if (iter.left == 0) {
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
			if (!_ro_graph.node_exists(node)) {
				_ro_graph.in().iter_set_to_end(iter);
				return;
			}
#endif
			_ro_graph.in_iter_begin_fast(iter, node);
		}
		else {
			w_edge* e = ((w_node*) iter.ptr)->wn_in_edges[--iter.left];
			iter.edge = (long) e;
#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
			if (g_tx_timestamp < e->we_timestamp_creation
					|| g_tx_timestamp >= e->we_timestamp_deletion) {
				in_iter_next_fast(iter);
			}
#else
			if (!e->exists()) {
				in_iter_next_fast(iter);
			}
#endif
#endif
		}
	}

	/**
	 * Determine if there are any more items left
	 *
	 * @param iter the iterator
	 * @return true if there are more items
	 */
	ITERATOR_DECL bool in_iter_has_next_fast(ll_edge_iterator& iter) {

		if (iter.owner != LL_I_OWNER_WRITABLE) {
			return _ro_graph.in_iter_has_next_fast(iter);
		}

		return iter.edge != LL_NIL_EDGE;
	}

	/**
	 * Get the next item
	 *
	 * @param iter the iterator
	 * @return the next item, or LL_NIL_EDGE if none
	 */
	ITERATOR_DECL edge_t in_iter_next_fast(ll_edge_iterator& iter) {

		if (iter.owner != LL_I_OWNER_WRITABLE) {
			return _ro_graph.in_iter_next_fast(iter);
		}

		edge_t r = iter.edge;
		if (r == LL_NIL_EDGE) return LL_NIL_EDGE;

		iter.last_node = ((w_edge*) r)->we_source;

		w_edge* e;
		do {
			if (iter.left == 0)	{
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
				if (!_ro_graph.node_exists(iter.node)) {
					_ro_graph.in().iter_set_to_end(iter);
					break;
				}
#endif
				_ro_graph.in_iter_begin_fast(iter, iter.node);
				break;
			}

			assert(iter.left > 0);
			e = ((w_node*) iter.ptr)->wn_in_edges[--iter.left];
			iter.edge = (long) e;

#ifdef LL_DELETIONS
		}
#ifdef LL_TIMESTAMPS
		while (g_tx_timestamp < e->we_timestamp_creation
				|| g_tx_timestamp >= e->we_timestamp_deletion);
#else
		while (!e->exists());
#endif
#elif 0
		{
#else
			break;
		}
		while (true);
#endif

		return LL_W_EDGE_CREATE(r);
	}

	/**
	 * Create iterator over all incoming nodes
	 *
	 * @param iter the iterator
	 * @param node the node
	 * @return the iterator
	 */
	void inm_iter_begin(ll_edge_iterator& iter, node_t node) {

		w_node* r = (w_node*) _vertices.get(node);
		if (r == NULL) {
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
			if (!_ro_graph.node_exists(node)) {
				_ro_graph.in().iter_set_to_end(iter);
				LL_D_NODE_PRINT(node, "Node does not exist\n");
				return;
			}
#endif
			LL_D_NODE_PRINT(node, "Not in ll_writable_graph, descending\n");
			_ro_graph.inm_iter_begin(iter, node, _ro_graph.num_levels()-1,
					_ro_graph.num_levels());
			return;
		}

		// Check if the node is deleted

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
		long t = LL_TX_TIMESTAMP;
		if (t < r->wn_timestamp_creation
				|| t >= r->wn_timestamp_deletion) {
			_ro_graph.in().iter_set_to_end(iter);
			LL_D_NODE_PRINT(node, "Deleted at timestamp %ld\n",
					r->wn_timestamp_deletion);
			return;
		}
#else
		if (!r->exists()) {
			_ro_graph.in().iter_set_to_end(iter);
			LL_D_NODE_PRINT(node, "Deleted\n");
			return;
		}
#endif
#endif

		// Create the iterator struct

		iter.owner = LL_I_OWNER_WRITABLE;
		iter.ptr = r;
		iter.node = node;
		iter.left = r->wn_in_edges.size();

		if (iter.left == 0) {
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
			if (!_ro_graph.node_exists(node)) {
				_ro_graph.in().iter_set_to_end(iter);
				return;
			}
#endif
			_ro_graph.inm_iter_begin(iter, node, _ro_graph.num_levels()-1,
					_ro_graph.num_levels());
			LL_D_NODE_PRINT(node, "No writable edges, descending\n");
		}
		else {
			w_edge* e = ((w_node*) iter.ptr)->wn_in_edges[--iter.left];
			iter.edge = (long) e;

			LL_D_NODE_PRINT(node, "left=%lu\n", (size_t) iter.left);

#ifdef LL_DELETIONS
#ifdef LL_TIMESTAMPS
			if (g_tx_timestamp < e->we_timestamp_creation
					|| g_tx_timestamp >= e->we_timestamp_deletion) {
				inm_iter_next(iter);
			}
#else
			if (!e->exists()) {
				inm_iter_next(iter);
			}
#endif
#endif
		}
	}

	/**
	 * Determine if there are any more items left
	 *
	 * @param iter the iterator
	 * @return true if there are more items
	 */
	bool inm_iter_has_next(ll_edge_iterator& iter) {

		if (iter.owner != LL_I_OWNER_WRITABLE) {
			return _ro_graph.inm_iter_has_next(iter);
		}

		return iter.edge != LL_NIL_EDGE;
	}

	/**
	 * Get the next item
	 *
	 * @param iter the iterator
	 * @return the next node, or LL_NIL_EDGE if none
	 */
	node_t inm_iter_next(ll_edge_iterator& iter) {

		if (iter.owner != LL_I_OWNER_WRITABLE) {
			return _ro_graph.inm_iter_next(iter);
		}

		edge_t r = iter.edge;
		if (r == LL_NIL_EDGE) return LL_NIL_NODE;

		w_edge* e;
		do {
			if (iter.left == 0)	{
#ifndef LL_CHECK_NODE_EXISTS_IN_RO
				if (!_ro_graph.node_exists(iter.node)) {
					_ro_graph.in().iter_set_to_end(iter);
					break;
				}
#endif
				_ro_graph.inm_iter_begin(iter, iter.node, _ro_graph.num_levels()-1, _ro_graph.num_levels());
				break;
			}

			assert(iter.left > 0);
			e = ((w_node*) iter.ptr)->wn_in_edges[--iter.left];
			iter.edge = (long) e;

#ifdef LL_DELETIONS
		}
#ifdef LL_TIMESTAMPS
		while (g_tx_timestamp < e->we_timestamp_creation
				|| g_tx_timestamp >= e->we_timestamp_deletion);
#else
		while (!e->exists());
#endif
#elif 0
		{
#else
			break;
		}
		while (true);
#endif

		return ((w_edge*) r)->we_source;
	}

	/**
	 * Find the given edge
	 *
	 * @param source the source node
	 * @param target the target node
	 * @return the edge, or NIL_EDGE if it does not exist
	 */
	edge_t find(node_t source, node_t target) {

		ll_edge_iterator iter;
		this->out_iter_begin(iter, source);
		FOREACH_OUTEDGE_ITER(e, *this, iter) {
			if (iter.last_node == target) return e;
		}

		return LL_NIL_EDGE;
	}

	/**
	 * Set node property -- a placeholder
	 *
	 * @param props the property
	 * @param n the node
	 * @param val the value
	 */
	template<typename U>
	void set_node_prop(U* props, node_t n, U val) {
		props[n] = val;
	}

	/**
	 * Get a 32-bit node property
	 *
	 * @param name the property name
	 * @return the property if it exists, or NULL if not
	 */
	ll_mlcsr_node_property<uint32_t>* get_node_property_32(const char* name) {

		auto p = _ro_graph.get_node_property_32(name);
		if (p == NULL) return NULL;

		ll_spinlock_acquire(&_property_lock);
		if (!p->writable()) p->writable_init(_vertices.size());
		ll_spinlock_release(&_property_lock);

		return p;
	}

	/**
	 * Get a 64-bit node property
	 *
	 * @param name the property name
	 * @return the property if it exists, or NULL if not
	 */
	ll_mlcsr_node_property<uint64_t>* get_node_property_64(const char* name) {

		auto p = _ro_graph.get_node_property_64(name);
		if (p == NULL) return NULL;

		ll_spinlock_acquire(&_property_lock);
		if (!p->writable()) p->writable_init(_vertices.size());
		ll_spinlock_release(&_property_lock);

		return p;
	}

	/**
	 * Get a 32-bit edge property
	 *
	 * @param name the property name
	 * @return the property if it exists, or NULL if not
	 */
	ll_mlcsr_edge_property<uint32_t>* get_edge_property_32(const char* name) {

		auto p = _ro_graph.get_edge_property_32(name);
		if (p == NULL) return NULL;

		ll_spinlock_acquire(&_property_lock);
		if (!p->writable()) p->writable_init();
		ll_spinlock_release(&_property_lock);

		return p;
	}

#ifdef LL_S_WEIGHTS_INSTEAD_OF_DUPLICATE_EDGES

	/**
	 * Get the edge weight property for streaming
	 *
	 * @return the property
	 */
	inline ll_mlcsr_edge_property<uint32_t>* get_edge_weights_streaming() {

		auto p = _ro_graph.get_edge_weights_streaming();
		if (p == NULL) return NULL;

		if (!p->writable()) {
			ll_spinlock_acquire(&_property_lock);
			if (!p->writable()) p->writable_init();
			ll_spinlock_release(&_property_lock);
		}

		return p;
	}

#endif

	/**
	 * Get a 64-bit edge property
	 *
	 * @param name the property name
	 * @return the property if it exists, or NULL if not
	 */
	ll_mlcsr_edge_property<uint64_t>* get_edge_property_64(const char* name) {

		auto p = _ro_graph.get_edge_property_64(name);
		if (p == NULL) return NULL;

		ll_spinlock_acquire(&_property_lock);
		if (!p->writable()) p->writable_init();
		ll_spinlock_release(&_property_lock);

		return p;
	}

protected:

	/**
	 * The checkpoint data source adapter
	 */
	class checkpoint_adapter : public ll_mlcsr_checkpoint_source {

		ll_writable_graph& _owner;

	public:

		checkpoint_adapter(ll_writable_graph& owner) : _owner(owner) {}
		virtual ~checkpoint_adapter() {}

		virtual size_t num_new_nodes() { return _owner._newNodes.load(); }
		virtual size_t num_new_edges() { return _owner._newEdges.load(); }
		virtual size_t max_node_id() { return _owner._next_new_node_id - 1; }
		virtual ll_w_vt_vertices_t* vertex_table() { return &_owner._vertices; }

		virtual void get_out_edges(node_t node, std::vector<node_t>& new_edges) {
			w_node* w = (w_node*) _owner._vertices.fast_get(node);
			size_t num = w->wn_out_edges.size();
			for (size_t i = 0; i < num; i++) {
				if (w->wn_out_edges[i]->exists()) {
					new_edges.push_back(w->wn_out_edges[i]->we_target);
				}
			}
		}
	};

	/**
	 * The external deletions adapter for the out-edges
	 */
	class deletions_adapter_out : public ll_mlcsr_external_deletions {

		ll_writable_graph& _owner;

	public:

		deletions_adapter_out(ll_writable_graph& owner) : _owner(owner) {}

		virtual bool is_edge_deleted(edge_t edge) {
#ifdef LL_DELETIONS
			ll_spinlock_acquire(&_owner._deletions_out_lock);
			auto it = _owner._deletions_out_map.find(edge);
			if (it != _owner._deletions_out_map.end()) {
#ifdef LL_TIMESTAMPS
				bool r = g_tx_timestamp >= it->second;
				ll_spinlock_release(&_owner._deletions_out_lock);
				return r;
#else
				ll_spinlock_release(&_owner._deletions_out_lock);
				return true;
#endif
			}
			ll_spinlock_release(&_owner._deletions_out_lock);
#endif
			return false;
		}
	};

	/**
	 * The external deletions adapter for the in-edges
	 */
	class deletions_adapter_in : public ll_mlcsr_external_deletions {

		ll_writable_graph& _owner;

	public:

		deletions_adapter_in(ll_writable_graph& owner) : _owner(owner) {}

		virtual bool is_edge_deleted(edge_t edge) {
#ifdef LL_DELETIONS
			ll_spinlock_acquire(&_owner._deletions_in_lock);
			auto it = _owner._deletions_in_map.find(edge);
			if (it != _owner._deletions_in_map.end()) {
#ifdef LL_TIMESTAMPS
				bool r = g_tx_timestamp >= it->second;
				ll_spinlock_release(&_owner._deletions_in_lock);
				return r;
#else
				ll_spinlock_release(&_owner._deletions_in_lock);
				return true;
#endif
			}
			ll_spinlock_release(&_owner._deletions_in_lock);
#endif
			return false;
		}
	};

public:

	/**
	 * Checkpoint
	 *
	 * @param config the loader config
	 */
	void checkpoint(const ll_loader_config* config = NULL) {

		if (_newNodes.load() == 0
				&& _delNodes.load() == 0
				&& _newEdges.load() == 0
				&& _delNewEdges.load() == 0
				&& _delFrozenEdges.load() == 0) return;

		ll_loader_config default_config;
		default_config.lc_reverse_edges = has_reverse_edges();
		default_config.lc_reverse_maps = has_reverse_edges()
			&& _ro_graph.out().has_edge_translation();
		const ll_loader_config* c = config == NULL ? &default_config : config;

		// Check whether we ran out of the level ID space, and if so, fail

		/*if (_ro_graph.num_levels() + 1 >= LL_MAX_LEVEL) {
			fprintf(stderr, "Fatal: Too many RO levels. Cannot recover!");
			abort();
		}*/

		// Create the new level

		checkpoint_adapter adapter(*this);

		__COMPILER_FENCE;
		_ro_graph.checkpoint(&adapter, c);
		__COMPILER_FENCE;

		// Clear the writable representation

		_newNodes.store(0);
		_delNodes.store(0);
		_newEdges.store(0);
		_delNewEdges.store(0);
		_delFrozenEdges.store(0);

		_vertices.clear();

#ifdef LL_WRITABLE_USE_MEMORY_POOL
		ll_free_w_pool();
#endif

		_deletions_out_map.clear();
		_deletions_in_map.clear();

		for (int i = 0; i < LL_D_STRIPES; i++) {
			_deletions_nodes_out[i].clear();
			_deletions_nodes_in[i].clear();
		}

		callback_ro_changed();

		// Check whether we ran out of the level ID space

		/*if (_ro_graph.num_levels() >= LL_MAX_LEVEL) {
			fprintf(stderr, "Error: Too many levels\n");
			abort();
		}*/
	}

	/**
	 * Delete a level
	 *
	 * @param level the level number
	 */
	void delete_level(size_t level) {

		_ro_graph.delete_level(level);
		callback_ro_changed();
	}

private:

	/*
	 * The read-only graph
	 */

	/// The read-only graph
	ll_mlcsr_ro_graph _ro_graph;

	/*
	 * The writable representation
	 */

	/// The adjacency lists
	ll_w_vt_vertices_t _vertices;

	/// Lock for creating new nodes
	ll_spinlock_t _new_node_lock;
	volatile node_t _next_new_node_id;

	/// The number of new and deleted nodes
	std::atomic<long> _newNodes;
	std::atomic<long> _delNodes;
	std::atomic<long> _newEdges;
	std::atomic<long> _delNewEdges;
	std::atomic<long> _delFrozenEdges;

	/*
	 * The deletions in the read-only graph
	 */

	/// The deletions adapters
	deletions_adapter_out _deletions_adapter_out;
	deletions_adapter_in _deletions_adapter_in;

	/// The deletions from the RO graph - map and a spinlock for out-edges
	std::unordered_map<edge_t, long> _deletions_out_map;
	ll_spinlock_t _deletions_out_lock;

	/// The deletions from the RO graph - map and a spinlock for in-edges
	std::unordered_map<edge_t, long> _deletions_in_map;
	ll_spinlock_t _deletions_in_lock;

	/// Affected nodes by the deletion of out-edges
	std::unordered_map<node_t, affected_node_by_edge_deletion_t> _deletions_nodes_out[LL_D_STRIPES];

	/// Affected nodes by the deletion of in-edges
	std::unordered_map<node_t, affected_node_by_edge_deletion_t> _deletions_nodes_in[LL_D_STRIPES];

	/*
	 * Properties
	 */

	/// The global property data-structures lock (don't care about performance)
	ll_spinlock_t _property_lock;

	/**
	 * Get a writable node, creating it if necessary, but not locking it
	 *
	 * @param node the node
	 * @return the node structure
	 */
	inline w_node* writable_node(node_t node) {
		w_node* r = (w_node*) _vertices.get_or_allocate(node);
		return r;
	}

	/**
	 * Get and lock a node, creating it if necessary
	 *
	 * @param node the node
	 * @return the node structure
	 */
	w_node* lock_node(node_t node) {
		w_node* r = (w_node*) _vertices.get_or_allocate(node);
		ll_spinlock_acquire(&r->wn_lock);

		// XXX Does this belong here? Certainly not if we have timestamps,
		// or if there is any way we need to initialize the node
		if (node >= _next_new_node_id) {
			ll_spinlock_acquire(&_new_node_lock);
			if (node >= _next_new_node_id) {
				_next_new_node_id = node + 1;
				_newNodes++;
			}
			ll_spinlock_release(&_new_node_lock);
		}

		return r;
	}

	/**
	 * Get and lock a node, creating it if necessary - but do not wait
	 *
	 * @param node the node
	 * @return the node structure, or NULL if already locked
	 */
	w_node* try_lock_node(node_t node) {
		w_node* r = (w_node*) _vertices.get_or_allocate(node);
		return ll_spinlock_try_acquire(&r->wn_lock) ? r : NULL;
	}

	/**
	 * Get and lock two nodes, creating them if necessary, and locking the
	 * node with the lower ID first, thus avoiding deadlocks through enforcing
	 * proper lock ordering
	 *
	 * @param node1 the node
	 * @param node2 the node
	 * @param p_node1 the pointer for the node structure
	 * @param p_node2 the pointer for the node structure
	 */
	void lock_nodes(node_t node1, node_t node2, w_node*& p_node1, w_node*& p_node2) {
		if (node1 == node2) {
			p_node1 = p_node2 = lock_node(node1);
		}
		else if (node1 < node2) {
			p_node1 = lock_node(node1);
			p_node2 = lock_node(node2);
		}
		else {
			p_node2 = lock_node(node2);
			p_node1 = lock_node(node1);
		}
	}

	/**
	 * Unlock a node
	 *
	 * @param node the node
	 */
	void release_node(w_node* node) {
		ll_spinlock_release(&node->wn_lock);
	}

	/**
	 * Unlock two nodes
	 *
	 * @param node1 node 1
	 * @param node2 node 2
	 */
	void release_nodes(w_node* node1, w_node* node2) {
		if (node1 == node2) {
			ll_spinlock_release(&node1->wn_lock);
		}
		else {
			ll_spinlock_release(&node1->wn_lock);
			ll_spinlock_release(&node2->wn_lock);
		}
	}
};

#endif /* LL_WRITABLE_GRAPH_H_ */


text:
package org.hl7.fhir.instance.model;

// Generated on Tue, Oct 21, 2014 07:07+1100 for FHIR v0.3.0

import java.util.*;

import java.math.*;
/**
 * A series of measurements taken by a device, with upper and lower limits. There may be more than one dimension in the data.
 */
public class SampledData extends Type {

    /**
     * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series.
     */
    protected Quantity origin;

    /**
     * The length of time between sampling times, measured in milliseconds.
     */
    protected DecimalType period;

    /**
     * A correction factor that is applied to the sampled data points before they are added to the origin.
     */
    protected DecimalType factor;

    /**
     * The lower limit of detection of the measured points. This is needed if any of the data points have the value "L" (lower than detection limit).
     */
    protected DecimalType lowerLimit;

    /**
     * The upper limit of detection of the measured points. This is needed if any of the data points have the value "U" (higher than detection limit).
     */
    protected DecimalType upperLimit;

    /**
     * The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once.
     */
    protected IntegerType dimensions;

    /**
     * A series of data points which are decimal values separated by a single space (character u20). The special values "E" (error), "L" (below detection limit) and "U" (above detection limit) can also be used in place of a decimal value.
     */
    protected StringType data;

    private static final long serialVersionUID = 173820410L;

    public SampledData() {
      super();
    }

    public SampledData(Quantity origin, DecimalType period, IntegerType dimensions, StringType data) {
      super();
      this.origin = origin;
      this.period = period;
      this.dimensions = dimensions;
      this.data = data;
    }

    /**
     * @return {@link #origin} (The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series.)
     */
    public Quantity getOrigin() {
      return this.origin;
    }

    /**
     * @param value {@link #origin} (The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series.)
     */
    public SampledData setOrigin(Quantity value) {
      this.origin = value;
      return this;
    }

    /**
     * @return {@link #period} (The length of time between sampling times, measured in milliseconds.). This is the underlying object with id, value and extensions. The accessor "getPeriod" gives direct access to the value
     */
    public DecimalType getPeriodElement() {
      return this.period;
    }

    /**
     * @param value {@link #period} (The length of time between sampling times, measured in milliseconds.). This is the underlying object with id, value and extensions. The accessor "getPeriod" gives direct access to the value
     */
    public SampledData setPeriodElement(DecimalType value) {
      this.period = value;
      return this;
    }

    /**
     * @return The length of time between sampling times, measured in milliseconds.
     */
    public BigDecimal getPeriod() {
      return this.period == null ? null : this.period.getValue();
    }

    /**
     * @param value The length of time between sampling times, measured in milliseconds.
     */
    public SampledData setPeriod(BigDecimal value) {
        if (this.period == null)
          this.period = new DecimalType();
        this.period.setValue(value);
      return this;
    }

    /**
     * @return {@link #factor} (A correction factor that is applied to the sampled data points before they are added to the origin.). This is the underlying object with id, value and extensions. The accessor "getFactor" gives direct access to the value
     */
    public DecimalType getFactorElement() {
      return this.factor;
    }

    /**
     * @param value {@link #factor} (A correction factor that is applied to the sampled data points before they are added to the origin.). This is the underlying object with id, value and extensions. The accessor "getFactor" gives direct access to the value
     */
    public SampledData setFactorElement(DecimalType value) {
      this.factor = value;
      return this;
    }

    /**
     * @return A correction factor that is applied to the sampled data points before they are added to the origin.
     */
    public BigDecimal getFactor() {
      return this.factor == null ? null : this.factor.getValue();
    }

    /**
     * @param value A correction factor that is applied to the sampled data points before they are added to the origin.
     */
    public SampledData setFactor(BigDecimal value) {
      if (value == null)
        this.factor = null;
      else {
        if (this.factor == null)
          this.factor = new DecimalType();
        this.factor.setValue(value);
      }
      return this;
    }

    /**
     * @return {@link #lowerLimit} (The lower limit of detection of the measured points. This is needed if any of the data points have the value "L" (lower than detection limit).). This is the underlying object with id, value and extensions. The accessor "getLowerLimit" gives direct access to the value
     */
    public DecimalType getLowerLimitElement() {
      return this.lowerLimit;
    }

    /**
     * @param value {@link #lowerLimit} (The lower limit of detection of the measured points. This is needed if any of the data points have the value "L" (lower than detection limit).). This is the underlying object with id, value and extensions. The accessor "getLowerLimit" gives direct access to the value
     */
    public SampledData setLowerLimitElement(DecimalType value) {
      this.lowerLimit = value;
      return this;
    }

    /**
     * @return The lower limit of detection of the measured points. This is needed if any of the data points have the value "L" (lower than detection limit).
     */
    public BigDecimal getLowerLimit() {
      return this.lowerLimit == null ? null : this.lowerLimit.getValue();
    }

    /**
     * @param value The lower limit of detection of the measured points. This is needed if any of the data points have the value "L" (lower than detection limit).
     */
    public SampledData setLowerLimit(BigDecimal value) {
      if (value == null)
        this.lowerLimit = null;
      else {
        if (this.lowerLimit == null)
          this.lowerLimit = new DecimalType();
        this.lowerLimit.setValue(value);
      }
      return this;
    }

    /**
     * @return {@link #upperLimit} (The upper limit of detection of the measured points. This is needed if any of the data points have the value "U" (higher than detection limit).). This is the underlying object with id, value and extensions. The accessor "getUpperLimit" gives direct access to the value
     */
    public DecimalType getUpperLimitElement() {
      return this.upperLimit;
    }

    /**
     * @param value {@link #upperLimit} (The upper limit of detection of the measured points. This is needed if any of the data points have the value "U" (higher than detection limit).). This is the underlying object with id, value and extensions. The accessor "getUpperLimit" gives direct access to the value
     */
    public SampledData setUpperLimitElement(DecimalType value) {
      this.upperLimit = value;
      return this;
    }

    /**
     * @return The upper limit of detection of the measured points. This is needed if any of the data points have the value "U" (higher than detection limit).
     */
    public BigDecimal getUpperLimit() {
      return this.upperLimit == null ? null : this.upperLimit.getValue();
    }

    /**
     * @param value The upper limit of detection of the measured points. This is needed if any of the data points have the value "U" (higher than detection limit).
     */
    public SampledData setUpperLimit(BigDecimal value) {
      if (value == null)
        this.upperLimit = null;
      else {
        if (this.upperLimit == null)
          this.upperLimit = new DecimalType();
        this.upperLimit.setValue(value);
      }
      return this;
    }

    /**
     * @return {@link #dimensions} (The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once.). This is the underlying object with id, value and extensions. The accessor "getDimensions" gives direct access to the value
     */
    public IntegerType getDimensionsElement() {
      return this.dimensions;
    }

    /**
     * @param value {@link #dimensions} (The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once.). This is the underlying object with id, value and extensions. The accessor "getDimensions" gives direct access to the value
     */
    public SampledData setDimensionsElement(IntegerType value) {
      this.dimensions = value;
      return this;
    }

    /**
     * @return The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once.
     */
    public int getDimensions() {
      return this.dimensions == null ? null : this.dimensions.getValue();
    }

    /**
     * @param value The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once.
     */
    public SampledData setDimensions(int value) {
        if (this.dimensions == null)
          this.dimensions = new IntegerType();
        this.dimensions.setValue(value);
      return this;
    }

    /**
     * @return {@link #data} (A series of data points which are decimal values separated by a single space (character u20). The special values "E" (error), "L" (below detection limit) and "U" (above detection limit) can also be used in place of a decimal value.). This is the underlying object with id, value and extensions. The accessor "getData" gives direct access to the value
     */
    public StringType getDataElement() {
      return this.data;
    }

    /**
     * @param value {@link #data} (A series of data points which are decimal values separated by a single space (character u20). The special values "E" (error), "L" (below detection limit) and "U" (above detection limit) can also be used in place of a decimal value.). This is the underlying object with id, value and extensions. The accessor "getData" gives direct access to the value
     */
    public SampledData setDataElement(StringType value) {
      this.data = value;
      return this;
    }

    /**
     * @return A series of data points which are decimal values separated by a single space (character u20). The special values "E" (error), "L" (below detection limit) and "U" (above detection limit) can also be used in place of a decimal value.
     */
    public String getData() {
      return this.data == null ? null : this.data.getValue();
    }

    /**
     * @param value A series of data points which are decimal values separated by a single space (character u20). The special values "E" (error), "L" (below detection limit) and "U" (above detection limit) can also be used in place of a decimal value.
     */
    public SampledData setData(String value) {
        if (this.data == null)
          this.data = new StringType();
        this.data.setValue(value);
      return this;
    }

      protected void listChildren(List<Property> childrenList) {
        super.listChildren(childrenList);
        childrenList.add(new Property("origin", "Quantity", "The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series.", 0, java.lang.Integer.MAX_VALUE, origin));
        childrenList.add(new Property("period", "decimal", "The length of time between sampling times, measured in milliseconds.", 0, java.lang.Integer.MAX_VALUE, period));
        childrenList.add(new Property("factor", "decimal", "A correction factor that is applied to the sampled data points before they are added to the origin.", 0, java.lang.Integer.MAX_VALUE, factor));
        childrenList.add(new Property("lowerLimit", "decimal", "The lower limit of detection of the measured points. This is needed if any of the data points have the value 'L' (lower than detection limit).", 0, java.lang.Integer.MAX_VALUE, lowerLimit));
        childrenList.add(new Property("upperLimit", "decimal", "The upper limit of detection of the measured points. This is needed if any of the data points have the value 'U' (higher than detection limit).", 0, java.lang.Integer.MAX_VALUE, upperLimit));
        childrenList.add(new Property("dimensions", "integer", "The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once.", 0, java.lang.Integer.MAX_VALUE, dimensions));
        childrenList.add(new Property("data", "string", "A series of data points which are decimal values separated by a single space (character u20). The special values 'E' (error), 'L' (below detection limit) and 'U' (above detection limit) can also be used in place of a decimal value.", 0, java.lang.Integer.MAX_VALUE, data));
      }

      public SampledData copy() {
        SampledData dst = new SampledData();
        dst.origin = origin == null ? null : origin.copy();
        dst.period = period == null ? null : period.copy();
        dst.factor = factor == null ? null : factor.copy();
        dst.lowerLimit = lowerLimit == null ? null : lowerLimit.copy();
        dst.upperLimit = upperLimit == null ? null : upperLimit.copy();
        dst.dimensions = dimensions == null ? null : dimensions.copy();
        dst.data = data == null ? null : data.copy();
        return dst;
      }

      protected SampledData typedCopy() {
        return copy();
      }

}


text:
<?php

function ___($content)
{
    $parts = explode('.', $content);

    if (!is_array($parts)) {
        return $content;
    }

    $translation = \App\Models\Core\Translations::where('locale', '=', strtolower(Session::get('locale')))->where('group', '=', $parts[0])->where('key', '=', $parts[1])->first();

    if (is_null($translation)) {
        return $content;
    }

    return ucfirst($translation->value);
}

function __($content)
{
    $parts = explode('.', $content);

    if (!is_array($parts)) {
        return $content;
    }
    $translation = \App\Models\Core\Translations::where('locale', '=', strtolower(Session::get('locale')))->where('group', '=', $parts[0])->where('key', '=', $parts[1])->first();

    if (is_null($translation)) {
        return $content;
    }

    return $translation->value;
}


text:
'use strict';
process.env.NODE_ENV = 'test'; //before every other instruction

const APIS = require('../../src/routes/apis');

let expect = require('chai').expect;
let app = require('../../app');
let agent = require('supertest').agent(app);

const TestUtils = require('../util/utils');
let testUtils = new TestUtils(agent);

const TestUsersUtils = require('../util/users');
let testUsersUtils = new TestUsersUtils(testUtils);

require('../../src/models/users');
let mongoose = require('mongoose');
// ------------------------
// as explained here http://mongoosejs.com/docs/promises.html
mongoose.Promise = require('bluebird');
// ------------------------
let User = mongoose.model('User');

const USER_NAME = 'username';
const USER_EMAIL = 'email@email.it';
const USER_PASSWORD = 'Password1';

const RESET_WRONG_EMAIL = 'notexisting@email.com';

const resetMock = {
	email : USER_EMAIL
};

const wrongResetMock = {
	email : RESET_WRONG_EMAIL
};

const URL_RESET = APIS.BASE_API_PATH + APIS.POST_LOCAL_RESET;

describe('auth-local', () => {

	describe('#reset()', () => {
		describe('---YES---', () => {

			beforeEach(done => testUsersUtils.insertUserTestDb(done));

			it('should correctly reset password', done => {
				testUtils.getPartialPostRequest(URL_RESET)
				.set('XSRF-TOKEN', testUtils.csrftoken)
				.send(resetMock)
				.expect(200)
				.end((err, res) => {
					if (err) {
						return done(err);
					}
          expect(res.body.message).to.be.equals('An e-mail has been sent to ' + USER_EMAIL + ' with further instructions.');
          if(err) {
            done(err);
          }
          User.findOne({ 'local.email': resetMock.email })
            .then(user => {
              expect(user.local.name).to.be.equals(USER_NAME);
              expect(user.local.email).to.be.equals(USER_EMAIL);
              expect(user.validPassword(USER_PASSWORD)).to.be.true;
              expect(user.local.resetPasswordExpires).to.be.not.null;
              expect(user.local.resetPasswordToken).to.be.not.null;
              expect(user.local.resetPasswordExpires).to.be.not.undefined;
              expect(user.local.resetPasswordToken).to.be.not.undefined;
              done();
            })
            .catch(err1 => done(err1));
				});
			});

			afterEach(done => testUsersUtils.dropUserTestDb(done));
		});

		describe('---NO - MISSING params---', () => {
			before(done => testUsersUtils.insertUserTestDb(done));

			const missingLoginMocks = [
				{email : null},
				{email : undefined},
				{}
			];

			//these are multiple tests that I'm execting for all cobinations
			//of wrong params
			for(let i = 0; i<missingLoginMocks.length; i++) {
				console.log(missingLoginMocks[i]);
				it('should get 400 BAD REQUEST, because email param is mandatory.', done => {
					testUtils.getPartialPostRequest(URL_RESET)
					.set('XSRF-TOKEN', testUtils.csrftoken)
					.send(missingLoginMocks[i])
					.expect(400)
					.end((err, res) => {
						if (err) {
							return done(err);
						}
            expect(res.body.message).to.be.equals("Email fields is required.");
            done();
					});
				});
			}

			it('should get 404 NOT FOUND, because the request email is not found.', done => {
				testUtils.getPartialPostRequest(URL_RESET)
				.set('XSRF-TOKEN', testUtils.csrftoken)
				.send({email : RESET_WRONG_EMAIL})
				.expect(404)
				.end((err, res) => {
					if (err) {
						return done(err);
					}
					console.log(res.body.message);
          expect(res.body.message).to.be.equals("No account with that email address exists.");
          done();
				});
			});

			after(done => testUsersUtils.dropUserTestDb(done));
		});

		describe('---ERRORS---', () => {
			it('should get 403 FORBIDDEN, because XSRF-TOKEN is not available', done => {
				testUtils.getPartialPostRequest(URL_RESET)
				//XSRF-TOKEN NOT SETTED!!!!
				.send(resetMock)
				.expect(403)
				.end(() => done());
			});
		});
	});
});


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

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/button_qrcode1"
          android:state_pressed="true" />
    <item android:drawable="@drawable/button_qrcode0"
          android:state_focused="true" />
    <item android:drawable="@drawable/button_qrcode0" />
</selector>


text:
import { mergeData } from 'vue-functional-data-merge'
import Link, { propsFactory as linkPropsFactory } from '../link/link'

export const props = linkPropsFactory()

export default {
  functional: true,
  props,
  render (h, { props, data, children }) {
    return h(
      'li',
      mergeData(data, {
        staticClass: 'nav-item'
      }),
      [h(Link, { staticClass: 'nav-link', props }, children)]
    )
  }
}