text:
package org.apache.phoenix.query;

import static org.apache.phoenix.util.PhoenixRuntime.CURRENT_SCN_ATTRIB;
import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL;
import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR;
import static org.apache.phoenix.util.PhoenixRuntime.PHOENIX_TEST_DRIVER_URL_PARAM;
import static org.apache.phoenix.util.TestUtil.ATABLE_NAME;
import static org.apache.phoenix.util.TestUtil.A_VALUE;
import static org.apache.phoenix.util.TestUtil.BTABLE_NAME;
import static org.apache.phoenix.util.TestUtil.B_VALUE;
import static org.apache.phoenix.util.TestUtil.CUSTOM_ENTITY_DATA_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.C_VALUE;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID1;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID2;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID3;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID4;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID5;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID6;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID7;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID8;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID9;
import static org.apache.phoenix.util.TestUtil.ENTITY_HISTORY_SALTED_TABLE_NAME;
import static org.apache.phoenix.util.TestUtil.ENTITY_HISTORY_TABLE_NAME;
import static org.apache.phoenix.util.TestUtil.E_VALUE;
import static org.apache.phoenix.util.TestUtil.FUNKY_NAME;
import static org.apache.phoenix.util.TestUtil.GROUPBYTEST_NAME;
import static org.apache.phoenix.util.TestUtil.HBASE_DYNAMIC_COLUMNS;
import static org.apache.phoenix.util.TestUtil.HBASE_NATIVE;
import static org.apache.phoenix.util.TestUtil.INDEX_DATA_SCHEMA;
import static org.apache.phoenix.util.TestUtil.INDEX_DATA_TABLE;
import static org.apache.phoenix.util.TestUtil.JOIN_COITEM_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.KEYONLY_NAME;
import static org.apache.phoenix.util.TestUtil.MDTEST_NAME;
import static org.apache.phoenix.util.TestUtil.MILLIS_IN_DAY;
import static org.apache.phoenix.util.TestUtil.MULTI_CF_NAME;
import static org.apache.phoenix.util.TestUtil.MUTABLE_INDEX_DATA_TABLE;
import static org.apache.phoenix.util.TestUtil.PARENTID1;
import static org.apache.phoenix.util.TestUtil.PARENTID2;
import static org.apache.phoenix.util.TestUtil.PARENTID3;
import static org.apache.phoenix.util.TestUtil.PARENTID4;
import static org.apache.phoenix.util.TestUtil.PARENTID5;
import static org.apache.phoenix.util.TestUtil.PARENTID6;
import static org.apache.phoenix.util.TestUtil.PARENTID7;
import static org.apache.phoenix.util.TestUtil.PARENTID8;
import static org.apache.phoenix.util.TestUtil.PARENTID9;
import static org.apache.phoenix.util.TestUtil.PRODUCT_METRICS_NAME;
import static org.apache.phoenix.util.TestUtil.PTSDB2_NAME;
import static org.apache.phoenix.util.TestUtil.PTSDB3_NAME;
import static org.apache.phoenix.util.TestUtil.PTSDB_NAME;
import static org.apache.phoenix.util.TestUtil.ROW1;
import static org.apache.phoenix.util.TestUtil.ROW2;
import static org.apache.phoenix.util.TestUtil.ROW3;
import static org.apache.phoenix.util.TestUtil.ROW4;
import static org.apache.phoenix.util.TestUtil.ROW5;
import static org.apache.phoenix.util.TestUtil.ROW6;
import static org.apache.phoenix.util.TestUtil.ROW7;
import static org.apache.phoenix.util.TestUtil.ROW8;
import static org.apache.phoenix.util.TestUtil.ROW9;
import static org.apache.phoenix.util.TestUtil.STABLE_NAME;
import static org.apache.phoenix.util.TestUtil.TABLE_WITH_ARRAY;
import static org.apache.phoenix.util.TestUtil.TABLE_WITH_SALTING;
import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import javax.annotation.Nonnull;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.IntegrationTestingUtility;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.end2end.BaseClientManagedTimeIT;
import org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver;
import org.apache.phoenix.jdbc.PhoenixTestDriver;
import org.apache.phoenix.schema.NewerTableAlreadyExistsException;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.TableAlreadyExistsException;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.util.ConfigUtil;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.QueryUtil;
import org.apache.phoenix.util.ReadOnlyProps;
import org.apache.phoenix.util.SchemaUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 *
 * Base class that contains all the methods needed by
 * client-time and hbase-time managed tests.
 *
 * For tests needing connectivity to a cluster, please use
 * {@link BaseHBaseManagedTimeIT} or {@link BaseClientManagedTimeIT}.
 *
 * In the rare case when a test can't share the same mini cluster as the
 * ones used by {@link BaseHBaseManagedTimeIT} or {@link BaseClientManagedTimeIT}
 * one could extend this class and spin up your own mini cluster. Please
 * make sure to shutdown the mini cluster in a method annotated by @AfterClass.
 *
 */
public abstract class BaseTest {
    private static final Map<String,String> tableDDLMap;
    private static final Logger logger = LoggerFactory.getLogger(BaseTest.class);

    static {
        ImmutableMap.Builder<String,String> builder = ImmutableMap.builder();
        builder.put(ENTITY_HISTORY_TABLE_NAME,"create table " + ENTITY_HISTORY_TABLE_NAME +
                "   (organization_id char(15) not null,\n" +
                "    parent_id char(15) not null,\n" +
                "    created_date date not null,\n" +
                "    entity_history_id char(15) not null,\n" +
                "    old_value varchar,\n" +
                "    new_value varchar,\n" + //create table shouldn't blow up if the last column definition ends with a comma.
                "    CONSTRAINT pk PRIMARY KEY (organization_id, parent_id, created_date, entity_history_id)\n" +
                ")");
        builder.put(ENTITY_HISTORY_SALTED_TABLE_NAME,"create table " + ENTITY_HISTORY_SALTED_TABLE_NAME +
                "   (organization_id char(15) not null,\n" +
                "    parent_id char(15) not null,\n" +
                "    created_date date not null,\n" +
                "    entity_history_id char(15) not null,\n" +
                "    old_value varchar,\n" +
                "    new_value varchar\n" +
                "    CONSTRAINT pk PRIMARY KEY (organization_id, parent_id, created_date, entity_history_id))\n" +
                "    SALT_BUCKETS = 4");
        builder.put(ATABLE_NAME,"create table " + ATABLE_NAME +
                "   (organization_id char(15) not null, \n" +
                "    entity_id char(15) not null,\n" +
                "    a_string varchar(100),\n" +
                "    b_string varchar(100),\n" +
                "    a_integer integer,\n" +
                "    a_date date,\n" +
                "    a_time time,\n" +
                "    a_timestamp timestamp,\n" +
                "    x_decimal decimal(31,10),\n" +
                "    x_long bigint,\n" +
                "    x_integer integer,\n" +
                "    y_integer integer,\n" +
                "    a_byte tinyint,\n" +
                "    a_short smallint,\n" +
                "    a_float float,\n" +
                "    a_double double,\n" +
                "    a_unsigned_float unsigned_float,\n" +
                "    a_unsigned_double unsigned_double\n" +
                "    CONSTRAINT pk PRIMARY KEY (organization_id, entity_id)\n" +
                ") ");
        builder.put(TABLE_WITH_ARRAY, "create table "
				+ TABLE_WITH_ARRAY
				+ "   (organization_id char(15) not null, \n"
				+ "    entity_id char(15) not null,\n"
				+ "    a_string_array varchar(100) array[],\n"
				+ "    b_string varchar(100),\n"
				+ "    a_integer integer,\n"
				+ "    a_date date,\n"
				+ "    a_time time,\n"
				+ "    a_timestamp timestamp,\n"
				+ "    x_decimal decimal(31,10),\n"
				+ "    x_long_array bigint array[],\n"
				+ "    x_integer integer,\n"
				+ "    a_byte_array tinyint array[],\n"
				+ "    a_short smallint,\n"
				+ "    a_float float,\n"
				+ "    a_double_array double array[],\n"
				+ "    a_unsigned_float unsigned_float,\n"
				+ "    a_unsigned_double unsigned_double \n"
				+ "    CONSTRAINT pk PRIMARY KEY (organization_id, entity_id)\n"
				+ ")");
        builder.put(BTABLE_NAME,"create table " + BTABLE_NAME +
                "   (a_string varchar not null, \n" +
                "    a_id char(3) not null,\n" +
                "    b_string varchar not null, \n" +
                "    a_integer integer not null, \n" +
                "    c_string varchar(2) null,\n" +
                "    b_integer integer,\n" +
                "    c_integer integer,\n" +
                "    d_string varchar(3),\n" +
                "    e_string char(10)\n" +
                "    CONSTRAINT my_pk PRIMARY KEY (a_string,a_id,b_string,a_integer,c_string))");
        builder.put(TABLE_WITH_SALTING,"create table " + TABLE_WITH_SALTING +
                "   (a_integer integer not null, \n" +
                "    a_string varchar not null, \n" +
                "    a_id char(3) not null,\n" +
                "    b_string varchar, \n" +
                "    b_integer integer \n" +
                "    CONSTRAINT pk PRIMARY KEY (a_integer, a_string, a_id))\n" +
                "    SALT_BUCKETS = 4");
        builder.put(STABLE_NAME,"create table " + STABLE_NAME +
                "   (id char(1) not null primary key,\n" +
                "    \"value\" integer)");
        builder.put(PTSDB_NAME,"create table " + PTSDB_NAME +
                "   (inst varchar null,\n" +
                "    host varchar null,\n" +
                "    date date not null,\n" +
                "    val decimal(31,10)\n" +
                "    CONSTRAINT pk PRIMARY KEY (inst, host, date))");
        builder.put(PTSDB2_NAME,"create table " + PTSDB2_NAME +
                "   (inst varchar(10) not null,\n" +
                "    date date not null,\n" +
                "    val1 decimal,\n" +
                "    val2 decimal(31,10),\n" +
                "    val3 decimal\n" +
                "    CONSTRAINT pk PRIMARY KEY (inst, date))");
        builder.put(PTSDB3_NAME,"create table " + PTSDB3_NAME +
                "   (host varchar(10) not null,\n" +
                "    date date not null,\n" +
                "    val1 decimal,\n" +
                "    val2 decimal(31,10),\n" +
                "    val3 decimal\n" +
                "    CONSTRAINT pk PRIMARY KEY (host DESC, date DESC))");
        builder.put(FUNKY_NAME,"create table " + FUNKY_NAME +
                "   (\"foo!\" varchar not null primary key,\n" +
                "    \"1\".\"#@$\" varchar, \n" +
                "    \"1\".\"foo.bar-bas\" varchar, \n" +
                "    \"1\".\"Value\" integer,\n" +
                "    \"1\".\"VALUE\" integer,\n" +
                "    \"1\".\"value\" integer,\n" +
                "    \"1\".\"_blah^\" varchar)"
                );
        builder.put(KEYONLY_NAME,"create table " + KEYONLY_NAME +
                "   (i1 integer not null, i2 integer not null\n" +
                "    CONSTRAINT pk PRIMARY KEY (i1,i2))");
        builder.put(MDTEST_NAME,"create table " + MDTEST_NAME +
                "   (id char(1) primary key,\n" +
                "    a.col1 integer,\n" +
                "    b.col2 bigint,\n" +
                "    b.col3 decimal,\n" +
                "    b.col4 decimal(5),\n" +
                "    b.col5 decimal(6,3))\n" +
                "    a." + HConstants.VERSIONS + "=" + 1 + "," + "a." + HColumnDescriptor.DATA_BLOCK_ENCODING + "='" + DataBlockEncoding.NONE +  "'");
        builder.put(MULTI_CF_NAME,"create table " + MULTI_CF_NAME +
                "   (id char(15) not null primary key,\n" +
                "    a.unique_user_count integer,\n" +
                "    b.unique_org_count integer,\n" +
                "    c.db_cpu_utilization decimal(31,10),\n" +
                "    d.transaction_count bigint,\n" +
                "    e.cpu_utilization decimal(31,10),\n" +
                "    f.response_time bigint,\n" +
                "    g.response_time bigint)");
        builder.put(GROUPBYTEST_NAME,"create table " + GROUPBYTEST_NAME +
                "   (id varchar not null primary key,\n" +
                "    uri varchar, appcpu integer)");
        builder.put(HBASE_NATIVE,"create table " + HBASE_NATIVE +
                "   (uint_key unsigned_int not null," +
                "    ulong_key unsigned_long not null," +
                "    string_key varchar not null,\n" +
                "    \"1\".uint_col unsigned_int," +
                "    \"1\".ulong_col unsigned_long" +
                "    CONSTRAINT pk PRIMARY KEY (uint_key, ulong_key, string_key))\n" +
                     HColumnDescriptor.DATA_BLOCK_ENCODING + "='" + DataBlockEncoding.NONE + "'");
        builder.put(HBASE_DYNAMIC_COLUMNS,"create table " + HBASE_DYNAMIC_COLUMNS +
                "   (entry varchar not null," +
                "    F varchar," +
                "    A.F1v1 varchar," +
                "    A.F1v2 varchar," +
                "    B.F2v1 varchar" +
                "    CONSTRAINT pk PRIMARY KEY (entry))\n");
        builder.put(PRODUCT_METRICS_NAME,"create table " + PRODUCT_METRICS_NAME +
                "   (organization_id char(15) not null," +
                "    date date not null," +
                "    feature char(1) not null," +
                "    unique_users integer not null,\n" +
                "    db_utilization decimal(31,10),\n" +
                "    transactions bigint,\n" +
                "    cpu_utilization decimal(31,10),\n" +
                "    response_time bigint,\n" +
                "    io_time bigint,\n" +
                "    region varchar,\n" +
                "    unset_column decimal(31,10)\n" +
                "    CONSTRAINT pk PRIMARY KEY (organization_id, DATe, feature, UNIQUE_USERS))");
        builder.put(CUSTOM_ENTITY_DATA_FULL_NAME,"create table " + CUSTOM_ENTITY_DATA_FULL_NAME +
                "   (organization_id char(15) not null, \n" +
                "    key_prefix char(3) not null,\n" +
                "    custom_entity_data_id char(12) not null,\n" +
                "    created_by varchar,\n" +
                "    created_date date,\n" +
                "    currency_iso_code char(3),\n" +
                "    deleted char(1),\n" +
                "    division decimal(31,10),\n" +
                "    last_activity date,\n" +
                "    last_update date,\n" +
                "    last_update_by varchar,\n" +
                "    name varchar(240),\n" +
                "    owner varchar,\n" +
                "    record_type_id char(15),\n" +
                "    setup_owner varchar,\n" +
                "    system_modstamp date,\n" +
                "    b.val0 varchar,\n" +
                "    b.val1 varchar,\n" +
                "    b.val2 varchar,\n" +
                "    b.val3 varchar,\n" +
                "    b.val4 varchar,\n" +
                "    b.val5 varchar,\n" +
                "    b.val6 varchar,\n" +
                "    b.val7 varchar,\n" +
                "    b.val8 varchar,\n" +
                "    b.val9 varchar\n" +
                "    CONSTRAINT pk PRIMARY KEY (organization_id, key_prefix, custom_entity_data_id))");
        builder.put("IntKeyTest","create table IntKeyTest" +
                "   (i integer not null primary key)");
        builder.put("IntIntKeyTest","create table IntIntKeyTest" +
                "   (i integer not null primary key, j integer)");
        builder.put("LongInKeyTest","create table LongInKeyTest" +
                "   (l bigint not null primary key)");
        builder.put("PKIntValueTest", "create table PKIntValueTest" +
                "   (pk integer not null primary key)");
        builder.put("PKBigIntValueTest", "create table PKBigIntValueTest" +
                "   (pk bigint not null primary key)");
        builder.put("PKUnsignedIntValueTest", "create table PKUnsignedIntValueTest" +
                "   (pk unsigned_int not null primary key)");
        builder.put("PKUnsignedLongValueTest", "create table PKUnsignedLongValueTest" +
                "   (pk unsigned_long not null\n" +
                "    CONSTRAINT pk PRIMARY KEY (pk))");
        builder.put("KVIntValueTest", "create table KVIntValueTest" +
                "   (pk integer not null primary key,\n" +
                "    kv integer)\n");
        builder.put("KVBigIntValueTest", "create table KVBigIntValueTest" +
                "   (pk integer not null primary key,\n" +
                "    kv bigint)\n");
        builder.put(INDEX_DATA_TABLE, "create table " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE + "(" +
                "   varchar_pk VARCHAR NOT NULL, " +
                "   char_pk CHAR(5) NOT NULL, " +
                "   int_pk INTEGER NOT NULL, "+
                "   long_pk BIGINT NOT NULL, " +
                "   decimal_pk DECIMAL(31, 10) NOT NULL, " +
                "   a.varchar_col1 VARCHAR, " +
                "   a.char_col1 CHAR(5), " +
                "   a.int_col1 INTEGER, " +
                "   a.long_col1 BIGINT, " +
                "   a.decimal_col1 DECIMAL(31, 10), " +
                "   b.varchar_col2 VARCHAR, " +
                "   b.char_col2 CHAR(5), " +
                "   b.int_col2 INTEGER, " +
                "   b.long_col2 BIGINT, " +
                "   b.decimal_col2 DECIMAL(31, 10) " +
                "   CONSTRAINT pk PRIMARY KEY (varchar_pk, char_pk, int_pk, long_pk DESC, decimal_pk)) " +
                "IMMUTABLE_ROWS=true");
        builder.put(MUTABLE_INDEX_DATA_TABLE, "create table " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + "(" +
                "   varchar_pk VARCHAR NOT NULL, " +
                "   char_pk CHAR(5) NOT NULL, " +
                "   int_pk INTEGER NOT NULL, "+
                "   long_pk BIGINT NOT NULL, " +
                "   decimal_pk DECIMAL(31, 10) NOT NULL, " +
                "   a.varchar_col1 VARCHAR, " +
                "   a.char_col1 CHAR(5), " +
                "   a.int_col1 INTEGER, " +
                "   a.long_col1 BIGINT, " +
                "   a.decimal_col1 DECIMAL(31, 10), " +
                "   b.varchar_col2 VARCHAR, " +
                "   b.char_col2 CHAR(5), " +
                "   b.int_col2 INTEGER, " +
                "   b.long_col2 BIGINT, " +
                "   b.decimal_col2 DECIMAL(31, 10) " +
                "   CONSTRAINT pk PRIMARY KEY (varchar_pk, char_pk, int_pk, long_pk DESC, decimal_pk)) "
                );
        builder.put("SumDoubleTest","create table SumDoubleTest" +
                "   (id varchar not null primary key, d DOUBLE, f FLOAT, ud UNSIGNED_DOUBLE, uf UNSIGNED_FLOAT, i integer, de decimal)");
        builder.put(JOIN_ORDER_TABLE_FULL_NAME, "create table " + JOIN_ORDER_TABLE_FULL_NAME +
                "   (\"order_id\" varchar(15) not null primary key, " +
                "    \"customer_id\" varchar(10), " +
                "    \"item_id\" varchar(10), " +
                "    price integer, " +
                "    quantity integer, " +
                "    date timestamp)");
        builder.put(JOIN_CUSTOMER_TABLE_FULL_NAME, "create table " + JOIN_CUSTOMER_TABLE_FULL_NAME +
                "   (\"customer_id\" varchar(10) not null primary key, " +
                "    name varchar, " +
                "    phone varchar(12), " +
                "    address varchar, " +
                "    loc_id varchar(5), " +
                "    date date)");
        builder.put(JOIN_ITEM_TABLE_FULL_NAME, "create table " + JOIN_ITEM_TABLE_FULL_NAME +
                "   (\"item_id\" varchar(10) not null primary key, " +
                "    name varchar, " +
                "    price integer, " +
                "    discount1 integer, " +
                "    discount2 integer, " +
                "    \"supplier_id\" varchar(10), " +
                "    description varchar)");
        builder.put(JOIN_SUPPLIER_TABLE_FULL_NAME, "create table " + JOIN_SUPPLIER_TABLE_FULL_NAME +
                "   (\"supplier_id\" varchar(10) not null primary key, " +
                "    name varchar, " +
                "    phone varchar(12), " +
                "    address varchar, " +
                "    loc_id varchar(5))");
        builder.put(JOIN_COITEM_TABLE_FULL_NAME, "create table " + JOIN_COITEM_TABLE_FULL_NAME +
                "   (item_id varchar(10) NOT NULL, " +
                "    item_name varchar NOT NULL, " +
                "    co_item_id varchar(10), " +
                "    co_item_name varchar " +
                "   CONSTRAINT pk PRIMARY KEY (item_id, item_name)) " +
                "   SALT_BUCKETS=4");
        tableDDLMap = builder.build();
    }

    private static final String ORG_ID = "00D300000000XHP";
    private static final int NUM_SLAVES_BASE = 1;

    protected static String getZKClientPort(Configuration conf) {
        return conf.get(QueryServices.ZOOKEEPER_PORT_ATTRIB);
    }

    private static String url;
    protected static PhoenixTestDriver driver;
    private static boolean clusterInitialized = false;
    private static HBaseTestingUtility utility;
    protected static final Configuration config = HBaseConfiguration.create();

    protected static String getUrl() {
        if (!clusterInitialized) {
            throw new IllegalStateException("Cluster must be initialized before attempting to get the URL");
        }
        return url;
    }

    protected static String checkClusterInitialized(ReadOnlyProps overrideProps) {
        if (!clusterInitialized) {
            url = setUpTestCluster(config, overrideProps);
            clusterInitialized = true;
        }
        return url;
    }

    /**
     * Set up the test hbase cluster.
     * @param props TODO
     * @return url to be used by clients to connect to the cluster.
     */
    protected static String setUpTestCluster(@Nonnull Configuration conf, ReadOnlyProps overrideProps) {
        boolean isDistributedCluster = isDistributedClusterModeEnabled(conf);
        if (!isDistributedCluster) {
            return initMiniCluster(conf, overrideProps);
       } else {
            return initClusterDistributedMode(conf, overrideProps);
        }
    }

    protected static void destroyDriver() throws Exception {
        if (driver != null) {
            try {
                assertTrue(destroyDriver(driver));
            } finally {
                driver = null;
            }
        }
    }

    protected static void dropNonSystemTables() throws Exception {
        try {
            disableAndDropNonSystemTables();
        } finally {
            destroyDriver();
        }
    }

    protected static void tearDownMiniCluster() throws Exception {
        try {
            destroyDriver();
        } finally {
            try {
                if (utility != null) {
                    utility.shutdownMiniCluster();
                }
            } finally {
                utility = null;
                clusterInitialized = false;
            }
        }
    }

    protected static void setUpTestDriver(ReadOnlyProps props) throws Exception {
        String url = checkClusterInitialized(props);
        if (driver == null) {
            driver = initAndRegisterDriver(url, props);
        }
    }

    private static boolean isDistributedClusterModeEnabled(Configuration conf) {
        boolean isDistributedCluster = false;
        //check if the distributed mode was specified as a system property.
        isDistributedCluster = Boolean.parseBoolean(System.getProperty(IntegrationTestingUtility.IS_DISTRIBUTED_CLUSTER, "false"));
        if (!isDistributedCluster) {
           //fall back on hbase-default.xml or hbase-site.xml to check for distributed mode
           isDistributedCluster = conf.getBoolean(IntegrationTestingUtility.IS_DISTRIBUTED_CLUSTER, false);
        }
        return isDistributedCluster;
    }

    /**
     * Initialize the mini cluster using phoenix-test specific configuration.
     * @param overrideProps TODO
     * @return url to be used by clients to connect to the mini cluster.
     */
    private static String initMiniCluster(Configuration conf, ReadOnlyProps overrideProps) {
        setUpConfigForMiniCluster(conf, overrideProps);
        utility = new HBaseTestingUtility(conf);
        try {
            utility.startMiniCluster();
            // add shutdown hook to kill the mini cluster
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    try {
                        if (utility != null) utility.shutdownMiniCluster();
                    } catch (Exception e) {
                        logger.warn("Exception caught when shutting down mini cluster", e);
                    }
                }
            });
            return getLocalClusterUrl(utility);
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    protected static String getLocalClusterUrl(HBaseTestingUtility util) throws Exception {
        String url = QueryUtil.getConnectionUrl(new Properties(), util.getConfiguration());
        return url + PHOENIX_TEST_DRIVER_URL_PARAM;
    }

    /**
     * Initialize the cluster in distributed mode
     * @param overrideProps TODO
     * @return url to be used by clients to connect to the mini cluster.
     */
    private static String initClusterDistributedMode(Configuration conf, ReadOnlyProps overrideProps) {
        setTestConfigForDistribuedCluster(conf, overrideProps);
        try {
            IntegrationTestingUtility util =  new IntegrationTestingUtility(conf);
            utility = util;
            util.initializeCluster(NUM_SLAVES_BASE);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return JDBC_PROTOCOL + JDBC_PROTOCOL_TERMINATOR + PHOENIX_TEST_DRIVER_URL_PARAM;
    }

    private static void setTestConfigForDistribuedCluster(Configuration conf, ReadOnlyProps overrideProps) {
        setDefaultTestConfig(conf, overrideProps);
    }

    private static void setDefaultTestConfig(Configuration conf, ReadOnlyProps overrideProps) {
        ConfigUtil.setReplicationConfigIfAbsent(conf);
        QueryServices services = new PhoenixTestDriver().getQueryServices();
        for (Entry<String,String> entry : services.getProps()) {
            conf.set(entry.getKey(), entry.getValue());
        }
        //no point doing sanity checks when running tests.
        conf.setBoolean("hbase.table.sanity.checks", false);

        // override any defaults based on overrideProps
        for (Entry<String,String> entry : overrideProps) {
            conf.set(entry.getKey(), entry.getValue());
        }
    }

    public static Configuration setUpConfigForMiniCluster(Configuration conf) {
        return setUpConfigForMiniCluster(conf, ReadOnlyProps.EMPTY_PROPS);
    }

    public static Configuration setUpConfigForMiniCluster(Configuration conf, ReadOnlyProps overrideProps) {
        assertNotNull(conf);
        setDefaultTestConfig(conf, overrideProps);
        /*
         * The default configuration of mini cluster ends up spawning a lot of threads
         * that are not really needed by phoenix for test purposes. Limiting these threads
         * helps us in running several mini clusters at the same time without hitting
         * the threads limit imposed by the OS.
         */
        conf.setInt(HConstants.REGION_SERVER_HANDLER_COUNT, 5);
        conf.setInt(HConstants.REGION_SERVER_META_HANDLER_COUNT, 2);
        conf.setInt(HConstants.MASTER_HANDLER_COUNT, 2);
        conf.setInt("dfs.namenode.handler.count", 2);
        conf.setInt("dfs.namenode.service.handler.count", 2);
        conf.setInt("dfs.datanode.handler.count", 2);
        conf.setInt("ipc.server.read.threadpool.size", 2);
        conf.setInt("ipc.server.handler.threadpool.size", 2);
        conf.setInt("hbase.hconnection.threads.max", 2);
        conf.setInt("hbase.hconnection.threads.core", 2);
        conf.setInt("hbase.htable.threads.max", 2);
        conf.setInt("hbase.regionserver.hlog.syncer.count", 2);
        conf.setInt("hbase.hlog.asyncer.number", 2);
        conf.setInt("hbase.assignment.zkevent.workers", 5);
        conf.setInt("hbase.assignment.threads.max", 5);
        conf.setInt("hbase.catalogjanitor.interval", 5000);
        return conf;
    }

    /**
     * Create a {@link PhoenixTestDriver} and register it.
     * @return an initialized and registered {@link PhoenixTestDriver}
     */
    protected static PhoenixTestDriver initAndRegisterDriver(String url, ReadOnlyProps props) throws Exception {
        PhoenixTestDriver newDriver = new PhoenixTestDriver(props);
        DriverManager.registerDriver(newDriver);
        Driver oldDriver = DriverManager.getDriver(url);
        if (oldDriver != newDriver) {
            destroyDriver(oldDriver);
        }
        Connection conn = newDriver.connect(url, PropertiesUtil.deepCopy(TEST_PROPERTIES));
        conn.close();
        return newDriver;
    }

    //Close and unregister the driver.
    protected static boolean destroyDriver(Driver driver) {
        if (driver != null) {
            assert(driver instanceof PhoenixEmbeddedDriver);
            PhoenixEmbeddedDriver pdriver = (PhoenixEmbeddedDriver)driver;
            try {
                try {
                    pdriver.close();
                    return true;
                } finally {
                    DriverManager.deregisterDriver(driver);
                }
            } catch (Exception e) {
                logger.warn("Unable to close registered driver: " + driver, e);
            }
        }
        return false;
    }

    protected static String getOrganizationId() {
        return ORG_ID;
    }

    private static long timestamp;

    public static long nextTimestamp() {
        timestamp += 100;
        return timestamp;
    }

    protected static void ensureTableCreated(String url, String tableName) throws SQLException {
        ensureTableCreated(url, tableName, null, null);
    }

    protected static void ensureTableCreated(String url, String tableName, byte[][] splits) throws SQLException {
        ensureTableCreated(url, tableName, splits, null);
    }

    protected static void ensureTableCreated(String url, String tableName, Long ts) throws SQLException {
        ensureTableCreated(url, tableName, null, ts);
    }

    protected static void ensureTableCreated(String url, String tableName, byte[][] splits, Long ts) throws SQLException {
        String ddl = tableDDLMap.get(tableName);
        createTestTable(url, ddl, splits, ts);
    }

    protected static void createTestTable(String url, String ddl) throws SQLException {
        createTestTable(url, ddl, null, null);
    }

    protected static void createTestTable(String url, String ddl, byte[][] splits, Long ts) throws SQLException {
        createTestTable(url, ddl, splits, ts, true);
    }

    protected static void createTestTable(String url, String ddl, byte[][] splits, Long ts, boolean swallowTableAlreadyExistsException) throws SQLException {
        assertNotNull(ddl);
        StringBuilder buf = new StringBuilder(ddl);
        if (splits != null) {
            buf.append(" SPLIT ON (");
            for (int i = 0; i < splits.length; i++) {
                buf.append("?,");
            }
            buf.setCharAt(buf.length()-1, ')');
        }
        ddl = buf.toString();
        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts));
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            PreparedStatement stmt = conn.prepareStatement(ddl);
            if (splits != null) {
                for (int i = 0; i < splits.length; i++) {
                    stmt.setBytes(i+1, splits[i]);
                }
            }
            stmt.execute(ddl);
        } catch (TableAlreadyExistsException e) {
            if (! swallowTableAlreadyExistsException) {
                throw e;
            }
        } finally {
            conn.close();
        }
    }

    protected static byte[][] getDefaultSplits(String tenantId) {
        return new byte[][] {
            Bytes.toBytes(tenantId + "00A"),
            Bytes.toBytes(tenantId + "00B"),
            Bytes.toBytes(tenantId + "00C"),
            };
    }

    protected static void deletePriorTables(long ts, String url) throws Exception {
        deletePriorTables(ts, (String)null, url);
    }

    protected static void deletePriorTables(long ts, String tenantId, String url) throws Exception {
        Properties props = new Properties();
        if (ts != HConstants.LATEST_TIMESTAMP) {
            props.setProperty(CURRENT_SCN_ATTRIB, Long.toString(ts));
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            deletePriorTables(ts, conn, url);
            deletePriorSequences(ts, conn);
        }
        finally {
            conn.close();
        }
    }

    private static void deletePriorTables(long ts, Connection globalConn, String url) throws Exception {
        DatabaseMetaData dbmd = globalConn.getMetaData();
        // Drop VIEWs first, as we don't allow a TABLE with views to be dropped
        // Tables are sorted by TENANT_ID
        List<String[]> tableTypesList = Arrays.asList(new String[] {PTableType.VIEW.toString()}, new String[] {PTableType.TABLE.toString()});
        for (String[] tableTypes: tableTypesList) {
            ResultSet rs = dbmd.getTables(null, null, null, tableTypes);
            String lastTenantId = null;
            Connection conn = globalConn;
            while (rs.next()) {
                String fullTableName = SchemaUtil.getEscapedTableName(
                        rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM),
                        rs.getString(PhoenixDatabaseMetaData.TABLE_NAME));
                String ddl = "DROP " + rs.getString(PhoenixDatabaseMetaData.TABLE_TYPE) + " " + fullTableName;
                String tenantId = rs.getString(1);
                if (tenantId != null && !tenantId.equals(lastTenantId))  {
                    if (lastTenantId != null) {
                        conn.close();
                    }
                    // Open tenant-specific connection when we find a new one
                    Properties props = new Properties(globalConn.getClientInfo());
                    props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId);
                    conn = DriverManager.getConnection(url, props);
                    lastTenantId = tenantId;
                }
                try {
                    conn.createStatement().executeUpdate(ddl);
                } catch (NewerTableAlreadyExistsException ex) {
                    logger.info("Newer table " + fullTableName + " or its delete marker exists. Ignore current deletion");
                } catch (TableNotFoundException ex) {
                    logger.info("Table " + fullTableName + " is already deleted.");
                }
            }
            if (lastTenantId != null) {
                conn.close();
            }
        }
    }

    private static void deletePriorSequences(long ts, Connection conn) throws Exception {
        // TODO: drop tenant-specific sequences too
        ResultSet rs = conn.createStatement().executeQuery("SELECT "
                + PhoenixDatabaseMetaData.SEQUENCE_SCHEMA + ","
                + PhoenixDatabaseMetaData.SEQUENCE_NAME
                + " FROM " + PhoenixDatabaseMetaData.SEQUENCE_FULLNAME_ESCAPED);
        while (rs.next()) {
            conn.createStatement().execute("DROP SEQUENCE " + SchemaUtil.getEscapedTableName(rs.getString(1), rs.getString(2)));
        }
    }

    protected static void initSumDoubleValues(byte[][] splits, String url) throws Exception {
        ensureTableCreated(url, "SumDoubleTest", splits);
        Properties props = new Properties();
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement(
                    "upsert into " +
                    "SumDoubleTest(" +
                    "    id, " +
                    "    d, " +
                    "    f, " +
                    "    ud, " +
                    "    uf) " +
                    "VALUES (?, ?, ?, ?, ?)");
            stmt.setString(1, "1");
            stmt.setDouble(2, 0.001);
            stmt.setFloat(3, 0.01f);
            stmt.setDouble(4, 0.001);
            stmt.setFloat(5, 0.01f);
            stmt.execute();

            stmt.setString(1, "2");
            stmt.setDouble(2, 0.002);
            stmt.setFloat(3, 0.02f);
            stmt.setDouble(4, 0.002);
            stmt.setFloat(5, 0.02f);
            stmt.execute();

            stmt.setString(1, "3");
            stmt.setDouble(2, 0.003);
            stmt.setFloat(3, 0.03f);
            stmt.setDouble(4, 0.003);
            stmt.setFloat(5, 0.03f);
            stmt.execute();

            stmt.setString(1, "4");
            stmt.setDouble(2, 0.004);
            stmt.setFloat(3, 0.04f);
            stmt.setDouble(4, 0.004);
            stmt.setFloat(5, 0.04f);
            stmt.execute();

            stmt.setString(1, "5");
            stmt.setDouble(2, 0.005);
            stmt.setFloat(3, 0.05f);
            stmt.setDouble(4, 0.005);
            stmt.setFloat(5, 0.05f);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initATableValues(String tenantId, byte[][] splits, String url) throws Exception {
        initATableValues(tenantId, splits, null, url);
    }

    protected static void initATableValues(String tenantId, byte[][] splits, Date date, String url) throws Exception {
        initATableValues(tenantId, splits, date, null, url);
    }

    protected static void initATableValues(String tenantId, byte[][] splits, Date date, Long ts, String url) throws Exception {
        if (ts == null) {
            ensureTableCreated(url, ATABLE_NAME, splits);
        } else {
            ensureTableCreated(url, ATABLE_NAME, splits, ts-5);
        }

        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, Long.toString(ts-3));
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement(
                    "upsert into " +
                    "ATABLE(" +
                    "    ORGANIZATION_ID, " +
                    "    ENTITY_ID, " +
                    "    A_STRING, " +
                    "    B_STRING, " +
                    "    A_INTEGER, " +
                    "    A_DATE, " +
                    "    X_DECIMAL, " +
                    "    X_LONG, " +
                    "    X_INTEGER," +
                    "    Y_INTEGER," +
                    "    A_BYTE," +
                    "    A_SHORT," +
                    "    A_FLOAT," +
                    "    A_DOUBLE," +
                    "    A_UNSIGNED_FLOAT," +
                    "    A_UNSIGNED_DOUBLE)" +
                    "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            stmt.setString(1, tenantId);
            stmt.setString(2, ROW1);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, B_VALUE);
            stmt.setInt(5, 1);
            stmt.setDate(6, date);
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)1);
            stmt.setShort(12, (short) 128);
            stmt.setFloat(13, 0.01f);
            stmt.setDouble(14, 0.0001);
            stmt.setFloat(15, 0.01f);
            stmt.setDouble(16, 0.0001);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW2);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, C_VALUE);
            stmt.setInt(5, 2);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 1));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)2);
            stmt.setShort(12, (short) 129);
            stmt.setFloat(13, 0.02f);
            stmt.setDouble(14, 0.0002);
            stmt.setFloat(15, 0.02f);
            stmt.setDouble(16, 0.0002);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW3);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, E_VALUE);
            stmt.setInt(5, 3);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 2));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)3);
            stmt.setShort(12, (short) 130);
            stmt.setFloat(13, 0.03f);
            stmt.setDouble(14, 0.0003);
            stmt.setFloat(15, 0.03f);
            stmt.setDouble(16, 0.0003);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW4);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, B_VALUE);
            stmt.setInt(5, 4);
            stmt.setDate(6, date == null ? null : date);
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)4);
            stmt.setShort(12, (short) 131);
            stmt.setFloat(13, 0.04f);
            stmt.setDouble(14, 0.0004);
            stmt.setFloat(15, 0.04f);
            stmt.setDouble(16, 0.0004);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW5);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, C_VALUE);
            stmt.setInt(5, 5);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 1));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)5);
            stmt.setShort(12, (short) 132);
            stmt.setFloat(13, 0.05f);
            stmt.setDouble(14, 0.0005);
            stmt.setFloat(15, 0.05f);
            stmt.setDouble(16, 0.0005);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW6);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, E_VALUE);
            stmt.setInt(5, 6);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 2));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)6);
            stmt.setShort(12, (short) 133);
            stmt.setFloat(13, 0.06f);
            stmt.setDouble(14, 0.0006);
            stmt.setFloat(15, 0.06f);
            stmt.setDouble(16, 0.0006);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW7);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, B_VALUE);
            stmt.setInt(5, 7);
            stmt.setDate(6, date == null ? null : date);
            stmt.setBigDecimal(7, BigDecimal.valueOf(0.1));
            stmt.setLong(8, 5L);
            stmt.setInt(9, 5);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)7);
            stmt.setShort(12, (short) 134);
            stmt.setFloat(13, 0.07f);
            stmt.setDouble(14, 0.0007);
            stmt.setFloat(15, 0.07f);
            stmt.setDouble(16, 0.0007);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW8);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, C_VALUE);
            stmt.setInt(5, 8);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 1));
            stmt.setBigDecimal(7, BigDecimal.valueOf(3.9));
            long l = Integer.MIN_VALUE - 1L;
            assert(l < Integer.MIN_VALUE);
            stmt.setLong(8, l);
            stmt.setInt(9, 4);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte)8);
            stmt.setShort(12, (short) 135);
            stmt.setFloat(13, 0.08f);
            stmt.setDouble(14, 0.0008);
            stmt.setFloat(15, 0.08f);
            stmt.setDouble(16, 0.0008);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW9);
            stmt.setString(3, C_VALUE);
            stmt.setString(4, E_VALUE);
            stmt.setInt(5, 9);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 2));
            stmt.setBigDecimal(7, BigDecimal.valueOf(3.3));
            l = Integer.MAX_VALUE + 1L;
            assert(l > Integer.MAX_VALUE);
            stmt.setLong(8, l);
            stmt.setInt(9, 3);
            stmt.setInt(10, 300);
            stmt.setByte(11, (byte)9);
            stmt.setShort(12, (short) 0);
            stmt.setFloat(13, 0.09f);
            stmt.setDouble(14, 0.0009);
            stmt.setFloat(15, 0.09f);
            stmt.setDouble(16, 0.0009);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initATableValues(String tenantId, byte[][] splits, Date date, Long ts) throws Exception {
        initATableValues(tenantId, splits, date, ts, getUrl());
    }

    protected static void initEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts) throws Exception {
        initEntityHistoryTableValues(tenantId, splits, date, ts, getUrl());
    }

    protected static void initSaltedEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts) throws Exception {
        initSaltedEntityHistoryTableValues(tenantId, splits, date, ts, getUrl());
    }

    protected static void initEntityHistoryTableValues(String tenantId, byte[][] splits, String url) throws Exception {
        initEntityHistoryTableValues(tenantId, splits, null, null, url);
    }

    protected static void initEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, String url) throws Exception {
        initEntityHistoryTableValues(tenantId, splits, date, null, url);
    }

    private static void initEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts, String url) throws Exception {
        if (ts == null) {
            ensureTableCreated(url, ENTITY_HISTORY_TABLE_NAME, splits);
        } else {
            ensureTableCreated(url, ENTITY_HISTORY_TABLE_NAME, splits, ts-2);
        }

        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, ts.toString());
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement(
                    "upsert into " +
                    ENTITY_HISTORY_TABLE_NAME+
                    "(" +
                    "    ORGANIZATION_ID, " +
                    "    PARENT_ID, " +
                    "    CREATED_DATE, " +
                    "    ENTITY_HISTORY_ID, " +
                    "    OLD_VALUE, " +
                    "    NEW_VALUE) " +
                    "VALUES (?, ?, ?, ?, ?, ?)");
            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID1);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID1);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID2);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID2);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID3);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID3);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID4);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID4);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID5);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID5);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID6);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID6);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID7);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID7);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID8);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID8);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID9);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID9);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initSaltedEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts, String url) throws Exception {
        if (ts == null) {
            ensureTableCreated(url, ENTITY_HISTORY_SALTED_TABLE_NAME, splits);
        } else {
            ensureTableCreated(url, ENTITY_HISTORY_SALTED_TABLE_NAME, splits, ts-2);
        }

        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, ts.toString());
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement(
                    "upsert into " +
                    ENTITY_HISTORY_SALTED_TABLE_NAME+
                    "(" +
                    "    ORGANIZATION_ID, " +
                    "    PARENT_ID, " +
                    "    CREATED_DATE, " +
                    "    ENTITY_HISTORY_ID, " +
                    "    OLD_VALUE, " +
                    "    NEW_VALUE) " +
                    "VALUES (?, ?, ?, ?, ?, ?)");
            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID1);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID1);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID2);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID2);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID3);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID3);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID4);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID4);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID5);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID5);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID6);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID6);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID7);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID7);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID8);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID8);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID9);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID9);
            stmt.setString(5,  A_VALUE);
            stmt.setString(6,  B_VALUE);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    /**
     * Disable and drop all the tables except SYSTEM.CATALOG and SYSTEM.SEQUENCE
     */
    private static void disableAndDropNonSystemTables() throws Exception {
        HBaseAdmin admin = driver.getConnectionQueryServices(null, null).getAdmin();
        try {
            HTableDescriptor[] tables = admin.listTables();
            for (HTableDescriptor table : tables) {
                String schemaName = SchemaUtil.getSchemaNameFromFullName(table.getName());
                if (!QueryConstants.SYSTEM_SCHEMA_NAME.equals(schemaName)) {
                    admin.disableTable(table.getName());
                    admin.deleteTable(table.getName());
                }
            }
        } finally {
            admin.close();
        }
    }

    public static void assertOneOfValuesEqualsResultSet(ResultSet rs, List<List<Object>>... expectedResultsArray) throws SQLException {
        List<List<Object>> results = Lists.newArrayList();
        while (rs.next()) {
            List<Object> result = Lists.newArrayList();
            for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
                result.add(rs.getObject(i+1));
            }
            results.add(result);
        }
        for (int j = 0; j < expectedResultsArray.length; j++) {
            List<List<Object>> expectedResults = expectedResultsArray[j];
            Set<List<Object>> expectedResultsSet = Sets.newHashSet(expectedResults);
            Iterator<List<Object>> iterator = results.iterator();
            while (iterator.hasNext()) {
                if (expectedResultsSet.contains(iterator.next())) {
                    iterator.remove();
                }
            }
        }
        if (results.isEmpty()) return;
        fail("Unable to find " + results + " in " + Arrays.asList(expectedResultsArray));
    }

    /**
     * Asserts that we find the expected values in the result set. We don't know the order, since we don't always
     * have an order by and we're going through indexes, but we assert that each expected result occurs once as
     * expected (in any order).
     */
    public static void assertValuesEqualsResultSet(ResultSet rs, List<List<Object>> expectedResults) throws SQLException {
        int expectedCount = expectedResults.size();
        int count = 0;
        List<List<Object>> actualResults = Lists.newArrayList();
        List<Object> errorResult = null;
        while (rs.next() && errorResult == null) {
            List<Object> result = Lists.newArrayList();
            for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
                result.add(rs.getObject(i+1));
            }
            if (!expectedResults.contains(result)) {
                errorResult = result;
            }
            actualResults.add(result);
            count++;
        }
        assertTrue("Could not find " + errorResult + " in expected results: " + expectedResults + " with actual results: " + actualResults, errorResult == null);
        assertEquals(expectedCount, count);
    }

    public HBaseTestingUtility getUtility() {
        return utility;
    }
}


text:
package cn.howardliu.gear.monitor.custom.modeler;

import javax.management.MBeanParameterInfo;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * <br>created at 17-5-10
 *
 * @author liuxh
 * @version 1.0.0
 * @since 1.0.0
 */
public abstract class MethodInfo extends FeatureInfo {
    protected ReadWriteLock parametersLock = new ReentrantReadWriteLock();
    protected ParameterInfo[] parameters = new ParameterInfo[0];

    public ParameterInfo[] getSignature() {
        parametersLock.readLock().lock();
        try {
            return this.parameters;
        } finally {
            parametersLock.readLock().unlock();
        }
    }

    public MethodInfo addParameter(ParameterInfo parameter) {
        parametersLock.writeLock().lock();
        try {
            ParameterInfo[] results = new ParameterInfo[this.parameters.length + 1];
            System.arraycopy(this.parameters, 0, results, 0, this.parameters.length);
            results[this.parameters.length] = parameter;
            this.parameters = results;
            this.info = null;
        } finally {
            parametersLock.writeLock().unlock();
        }
        return this;
    }

    protected MBeanParameterInfo[] getMBeanParameterInfos() {
        ParameterInfo[] params = getSignature();
        MBeanParameterInfo[] parameters = new MBeanParameterInfo[params.length];
        for (int i = 0; i < params.length; i++) {
            parameters[i] = params[i].getInfo();
        }
        return parameters;
    }
}

redpajama_set_name: RedPajamaGithub


text:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
using FluentDock.Internals;

namespace FluentDock.Primitives
{
    public class SplitterItemsPanel : VirtualizingPanel
    {
        #region "Fields"

        private DispatcherOperation _currentOperation;
        private IList<SplitterGrip> _generatedSplitterGrips;
        private IDictionary<SplitterItem, Size> _measures = new Dictionary<SplitterItem, Size>();

        #endregion

        #region "Constructors"

        /// <summary>
        /// Initializes static members of the <see cref="SplitterItemsPanel"/> class.
        /// </summary>
        static SplitterItemsPanel()
        {

        }

        /// <summary>
        /// Initializes instance members of the <see cref="SplitterItemsPanel"/> class.
        /// </summary>
        public SplitterItemsPanel()
        {
            _generatedSplitterGrips = new List<SplitterGrip>();
        }

        #endregion

        #region "Properties"

        #region Length

        /// <summary>
        /// Length Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty LengthProperty = DependencyProperty.RegisterAttached(
            "Length",
            typeof(ItemLength),
            typeof(SplitterItemsPanel),
            new FrameworkPropertyMetadata(new ItemLength(1, ItemLengthUnitType.Star),
                (o, args) =>
                {
                    // we should invalidate the arrange of the parent
                    var item = (SplitterItem)o;

                    var itemsControl = ItemsControl.ItemsControlFromItemContainer(item) as DockGroupControl;
                    if (itemsControl != null && itemsControl.DisallowPanelInvalidation)
                        return;

                    var panel = DockGroupControl.PanelFromContainer(item);
                    if (panel != null)
                        panel.InvalidateMeasure();
                },
                (o, value) =>
                {
                    var length = (ItemLength)value;

                    if (length.Value < 0.0)
                        length.Value = 0.0;

                    return length;
                }));

        /// <summary>
        /// Gets the Length property. This dependency property
        /// indicates ....
        /// </summary>
        public static ItemLength GetLength(DependencyObject d)
        {
            return (ItemLength)d.GetValue(LengthProperty);
        }

        /// <summary>
        /// Sets the Length property. This dependency property
        /// indicates ....
        /// </summary>
        public static void SetLength(DependencyObject d, ItemLength value)
        {
            d.SetValue(LengthProperty, value);
        }

        #endregion

        #region Orientation

        /// <summary>
        /// Identifies the <see cref="Orientation"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
            "Orientation",
            typeof(Orientation),
            typeof(SplitterItemsPanel),
            new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsArrange));

        /// <summary>
        /// Gets or sets the Orientation property. This is a dependency property.
        /// </summary>
        /// <value>
        ///
        /// </value>
        [Bindable(true)]
        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        #endregion

        #region IndexForItemContainer

        private static readonly DependencyProperty IndexForItemContainerProperty = DependencyProperty.RegisterAttached(
            "IndexForItemContainer",
            typeof(int),
            typeof(SplitterItemsPanel),
            new FrameworkPropertyMetadata(-1));

        #endregion

        #endregion

        #region "Internal Properties"

        public DockGroupControl SplitterItemsControl
        {
            get { return TemplatedParent as DockGroupControl; }
        }

        private ItemsControl ItemsOwner
        {
            get { return ItemsControl.GetItemsOwner(this); }
        }

        private int ItemsCount
        {
            get
            {
                var itemsOwner = this.ItemsOwner;
                return itemsOwner == null ? 0 : itemsOwner.Items.Count;
            }
        }

        #endregion

        #region "Methods"

        protected override void OnIsItemsHostChanged(bool oldIsItemsHost, bool newIsItemsHost)
        {
            base.OnIsItemsHostChanged(oldIsItemsHost, newIsItemsHost);
            InvalidateContainers();
        }

        protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args)
        {
            base.OnItemsChanged(sender, args);
            InvalidateContainers();
        }

        private void InvalidateContainers()
        {
            if (_currentOperation != null)
                _currentOperation.Abort();

            Action action = delegate
            {
                _currentOperation = null;
                GenerateContainers();
            };

            _currentOperation = Dispatcher.BeginInvoke(action, DispatcherPriority.Normal);
        }

        private void GenerateContainers()
        {
            var internalChildren = InternalChildren;
            var generator = ItemContainerGenerator;
            var count = ItemsCount;

            if (count == 0)
            {
                return;
            }

            Cleanup(generator, InternalChildren.Cast<UIElement>().ToList());

            int index = -1;
            var previousContainer = GenerateChild(generator, ++index);
            while (index < (count - 1))
            {
                var splitter = GenerateSplitterGrip();
                var nextContainer = GenerateChild(generator, ++index);

                splitter.LeftChild = previousContainer;
                splitter.RightChild = nextContainer;
                previousContainer = nextContainer;
            }
        }

        private void Cleanup(IItemContainerGenerator generator, IEnumerable<UIElement> children)
        {
            foreach (var child in children)
            {
                var childIndex = InternalChildren.IndexOf(child);
                if (child is SplitterGrip)
                {
                    RemoveInternalChildRange(childIndex, 1);
                    _generatedSplitterGrips.Remove((SplitterGrip)child);
                    continue;
                }

                VirtualizeContainer(generator, child, childIndex);
            }
        }

        private void VirtualizeContainer(IItemContainerGenerator generator, UIElement container, int indexOf)
        {
            if (generator == null)
            {
                throw new ArgumentNullException("generator");
            }

            if (container == null)
            {
                throw new ArgumentNullException("container");
            }

            var index = (int)container.GetValue(IndexForItemContainerProperty);
            if (index == -1)
                return;

            container.ClearValue(IndexForItemContainerProperty);

            // remove from the visual tree
            RemoveInternalChildRange(indexOf, 1);

            // remove from the generator
            var trackPosition = generator.GeneratorPositionFromIndex(index);
            generator.Remove(trackPosition, 1);
        }

        private SplitterGrip GenerateSplitterGrip(int index = -1)
        {
            var splitterGrip = new SplitterGrip();
            if (index == -1)
            {
                this.AddInternalChild(splitterGrip);
            }
            else
            {
                InsertInternalChild(index, splitterGrip);
            }

            _generatedSplitterGrips.Add(splitterGrip);

            // set orientation binding to the panel
            this.DefineBinding(OrientationProperty, splitterGrip, SplitterGrip.OrientationProperty);
            return splitterGrip;
        }

        /// <summary>
        /// Will generate a container and measure it.
        /// </summary>
        private SplitterItem GenerateChild(IItemContainerGenerator generator, int index, int uiIndex = -1)
        {
            var position = generator.GeneratorPositionFromIndex(index);
            using (generator.StartAt(position, GeneratorDirection.Forward, false))
            {
                var container = (SplitterItem)generator.GenerateNext();
                container.SetValue(IndexForItemContainerProperty, index);

                if (uiIndex == -1)
                {
                    this.AddInternalChild(container);
                }
                else
                {
                    InsertInternalChild(uiIndex, container);
                }

                generator.PrepareItemContainer(container);
                return container;
            }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            _measures.Clear();
            var isVertical = Orientation == Orientation.Vertical;
            var count = ItemsCount;

            if (count == 0)
                return base.MeasureOverride(availableSize);

            // we only accept size with fixed width/height, based on the orientation.
            if (isVertical && double.IsPositiveInfinity(availableSize.Width))
                return base.MeasureOverride(availableSize);

            if (!isVertical && double.IsPositiveInfinity(availableSize.Height))
                return base.MeasureOverride(availableSize);

            var desiredSize = new Size();

            #region "Measure the Containers"

            var gripSize = SplitterItemsControl.GripLength;
            var splitterItems = InternalChildren.OfType<SplitterItem>().ToList();

            // the available space excluding the grips.
            var actualLength = isVertical
                ? Math.Max(0.0, availableSize.Width - (_generatedSplitterGrips.Count * gripSize))
                : Math.Max(0.0, availableSize.Height - (_generatedSplitterGrips.Count * gripSize));

            // space reserved for fixed size items.
            var fixedLength = splitterItems.Where(si => si.IsFixed)
                .Sum(si => si.Length.Value);

            actualLength = Math.Max(0.0, actualLength - fixedLength);

            var allSizes = splitterItems.Where(si => !si.IsFixed).Sum(si => si.Length.Value);
            var uniformSize = actualLength / allSizes;

            foreach (UIElement si in InternalChildren)
            {
                if (si is SplitterGrip)
                {
                    si.Measure(availableSize);
                    continue;
                }

                var splitterItem = (SplitterItem)si;
                var itemLength = splitterItem.IsFixed
                    ? splitterItem.Length.Value
                    : splitterItem.Length.Value * uniformSize;

                var childAvailableSize = isVertical
                    ? new Size(itemLength, availableSize.Height)
                    : new Size(availableSize.Width, itemLength);

                _measures.Add(splitterItem, childAvailableSize);
                splitterItem.Measure(childAvailableSize);
                var childDesiredSize = splitterItem.DesiredSize;

                if (isVertical)
                {
                    if (desiredSize.Height < childDesiredSize.Height)
                        desiredSize.Height = childDesiredSize.Height;
                }
                else
                {
                    if (desiredSize.Width < childDesiredSize.Width)
                        desiredSize.Width = childDesiredSize.Width;
                }
            }

            if (isVertical)
                desiredSize.Width = availableSize.Width;
            else
                desiredSize.Height = availableSize.Height;

            #endregion

            return desiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (_measures.Count == 0)
                return base.ArrangeOverride(finalSize);

            bool isVertical = Orientation == Orientation.Vertical;
            var rect = new Rect(finalSize);
            foreach (UIElement child in this.InternalChildren)
            {
                var desiredSize = child is SplitterGrip ? child.DesiredSize : _measures[(SplitterItem)child];
                if (isVertical)
                {
                    rect.Width = desiredSize.Width;
                    child.Arrange(rect);
                    rect.X += desiredSize.Width;
                }
                else
                {
                    rect.Height = desiredSize.Height;
                    child.Arrange(rect);
                    rect.Y += desiredSize.Height;
                }
            }

            return finalSize;
        }

        #endregion
    }
}


text:
export const Field: any;
export const Fieldset: any;
export const Form: any;
export const FormSection: any;


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bivi.Infrastructure.Services.Translation;
using Bivi.FrontOffice.Web.ViewModels.ViewModels;

namespace Bivi.FrontOffice.Web.ViewModels.Pages.Module
{
    public class PopinVideoViewModel
    {
        public ITranslator TranslatorService { get; set; }
        public RessourceViewModel RessourceData { get; set; }
        public bool External { get; set; }
    }
}


text:
#include "simplejson.h"
#include "slayer_utf8.h"

/* $Id: simplejson.c,v 1.6 2008/02/29 00:18:51 derek Exp $ */

/** create json_value objects **/

/** decode json from a string **/
json_value* decode_json_array(json_string *injson);
json_value* decode_json_boolean(json_string *injson);
json_value * decode_json_null(json_string *injson);
json_value* decode_json_number(json_string *injson);
json_value* decode_json_object(json_string *injson);
json_value* decode_json_string(json_string *injson);
json_value * decode_json_value(json_string *injson);

/** dump more than encode **/
void encode_json_object(json_value *json);
void encode_json_array(json_value *json);
void encode_json_boolean(json_value *json);
void encode_json_string(json_value *json);
void encode_json_null(json_value *json);
void encode_json_number(json_value *json);

typedef struct _json_link_t {
	json_value *value;
	struct _json_link_t *next;
} json_link_t;

json_value* decode_json_array(json_string *injson) {
	if(injson == NULL || injson->offset == NULL || injson->offset >= injson->end) return NULL;

	apr_pool_t *link_pool;

	json_link_t *head,*node;
	int link_count = 0;
	head = node = NULL;

	/*
	json_value *out = apr_palloc(injson->mpool,sizeof(json_value));
	out->value.array = apr_array_make(injson->mpool,100,sizeof(json_value *));
	out->type = JSON_ARRAY;
	*/

	injson->offset++; // toss of the leading [
	while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
	if(injson->offset >= injson->end) return NULL;
	if(*(injson->offset) == ']') {
		injson->offset++;
		return json_array_create(injson->mpool,1);
	}

	json_value *element = decode_json_value(injson);
	if(element==NULL) return NULL;
	apr_pool_create(&link_pool,NULL);
	head = node = apr_pcalloc(link_pool,sizeof(json_link_t));
	node->value = element;
	link_count++;
	//*((json_value**)(apr_array_push(out->value.array))) = element;

	while( injson->offset < injson->end && *(injson->offset)!=']') {
		while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
		if(injson->offset >= injson->end) return NULL;
		switch(*(injson->offset)) {
			case ']':
					goto array_closure;
			case ',':
					injson->offset++;
					if((element = decode_json_value(injson))==NULL) {
						apr_pool_destroy(link_pool);
						return NULL;
					}
					//*((json_value**)(apr_array_push(out->value.array))) = element;
					node->next = apr_pcalloc(link_pool,sizeof(json_link_t));
					node->next->value = element;
					node = node->next;
					link_count++;
					break;
			default:
					apr_pool_destroy(link_pool);
					return NULL;
		}
	}
array_closure:
		if(injson->offset >= injson->end || *(injson->offset) !=']'){
			apr_pool_destroy(link_pool);
			 return NULL;
		}
		injson->offset++; //chew up trailing ']'
		json_value *out = apr_palloc(injson->mpool,sizeof(json_value));
		out->value.array = apr_array_make(injson->mpool,link_count,sizeof(json_value *));
		out->type = JSON_ARRAY;
		node = head;
		while(node) {
			*((json_value**)(apr_array_push(out->value.array))) = node->value;
			node = node->next;
		}
		apr_pool_destroy(link_pool);
	return out;
}

json_value* decode_json_object(json_string *injson){

	if(injson == NULL || injson->offset == NULL) return NULL;

	json_value *out = apr_palloc(injson->mpool,sizeof(json_value));
	out->value.object = json_skip_create(injson->mpool,7,(json_skip_cmp_t)strcmp);
	out->type = JSON_OBJECT;

	injson->offset++; // toss of the leading  {
	while(isspace(*injson->offset)) injson->offset++;
	//empty { }
	if(*(injson->offset) == '}') {
		injson->offset++;
		return out;
	}

	//PULL OUT THE FIRST VALUE
	while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
	if(injson->offset >= injson->end || *(injson->offset) != '"') return NULL;
	json_value *name = decode_json_string(injson);
	if(name == NULL) return NULL;
	while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
	if(injson->offset >= injson->end || *(injson->offset) != ':') return NULL;
	injson->offset++; //eat the :
	while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
	json_value *value = decode_json_value(injson);
	if(value == NULL) return NULL;
	json_skip_put(out->value.object,name->value.string,value);

	while( injson->offset < injson->end && *(injson->offset) != '}') {
		while( injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
		if(injson->offset < injson->end && *(injson->offset) == '}')  {
			goto object_closure;
		} else if (injson->offset < injson->end &&*(injson->offset) == ',') {
			injson->offset++; // eat the comma
			while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
			if(injson->offset >= injson->end || *(injson->offset) != '"') return NULL;
			json_value *name = decode_json_string(injson);
			if(name == NULL) return NULL;
			while(injson->offset < injson->end &&isspace(*injson->offset)) injson->offset++;
			if(injson->offset >= injson->end ||*(injson->offset) != ':') return NULL;
			injson->offset++;
			while(injson->offset < injson->end && isspace(*injson->offset)) injson->offset++;
			json_value *value = decode_json_value(injson);
			if(value == NULL) return NULL;
			json_skip_put(out->value.object,name->value.string,value);
		} else {
			return NULL;
		}
	}
object_closure:
		if(injson->offset >= injson->end ||*(injson->offset) !='}') return NULL;
		injson->offset++; //chew up trailing '}'
	return out;
}

json_value* decode_json_string(json_string *injson) {
	json_value *out = NULL;
	const char *ptr;
	injson->offset++; //advance past the \"
	ptr = injson->offset;
	while( ptr< injson->end && *ptr !='"') {
			if(*ptr == '\\') {
							ptr++;
							switch(*ptr) {
								case 'u':
								case '\\':
								case '/':
								case 'n':
								case 'r':
								case 't':
								case 'f':
								case 'b':
								case '"':
									break;
								default:
									return NULL;
							}
			}
			ptr++;
	}
	//make sure the string is terminated w/ "
	if(ptr >= injson->end) return NULL;

	int vsize  = (ptr - injson->offset) + 1;
	out = apr_palloc(injson->mpool,sizeof(json_value));
	out->value.string = apr_palloc(injson->mpool,vsize);
	memset(out->value.string,0,vsize);
	out->type = JSON_STRING;
	char * optr =  out->value.string;
	while( injson->offset <  injson->end && *(injson->offset) !='"') {
		if(*(injson->offset) == '\\') {
			injson->offset++;
			if(injson->offset >= injson->end )  { return NULL; }
			switch(*(injson->offset)) {
				case 'u':  // we are not excepting this for now - use UTF-8
					/** THIS IS REQUIRED TO A 4 DIGIT HEX NUMBER **/
					{
						if(strlen(injson->offset+1)<4) return NULL;
						char code[5];
						code[4] = '\0';
						memcpy(code,injson->offset+1,4); //copy 4 digit
						int value = slayer_hex2int(code);
						if(value == -1) return NULL; //contained something other than 0-9A-Fa-f
						char *encode = slayer_escaped2utf8(injson->mpool,value);
						if(encode == NULL) return NULL; //not a valid range
						while( *encode!='\0') *optr++ = *encode++;
						injson->offset+=4; // it will get the U at the end
					}
					break;
				case '\\':
					*optr =  '\\'; optr++;
					break;
				case '/':
					*optr =  '/'; optr++;
					break;
				case 'n':
					*optr =  '\n'; optr++;
					break;
				case 'r':
					*optr =  '\r'; optr++;
					break;
				case 't':
					*optr =  '\t'; optr++;
					break;
				case 'f':
					*optr =  '\f'; optr++;
					break;
				case 'b':
					*optr =  '\b'; optr++;
					break;
				case '"':
					*optr =  '"'; optr++;
					break;
				default:
					//should be impossible
					return NULL;
			}
		} else {
			*optr = *(injson->offset);
			optr++;
		}
		injson->offset++;
	}
	if(injson->offset >= injson->end ||*(injson->offset) != '"')  { return NULL; }
	injson->offset++;
	return out;
}
json_value* decode_json_boolean(json_string *injson){
	json_value *out = NULL;
	if(injson->end - injson->offset > 3  && strncmp("true",injson->offset,4) == 0) {
		out = apr_palloc(injson->mpool,sizeof(json_value));
		out->value.boolean = 1;
		out->type = JSON_BOOLEAN;
		injson->offset +=4;
	} else if (injson->end - injson->offset > 4 && strncmp("false",injson->offset,5)==0){
		out = apr_palloc(injson->mpool,sizeof(json_value));
		out->value.boolean = 0;
		out->type = JSON_BOOLEAN;
		injson->offset +=5;
	}
	return out;
}

json_value* decode_json_number(json_string *injson){
	json_value *out = NULL;
	char *optr = (char*)injson->end;
	const char *pptr = injson->offset;
	char isfloat = 0;
	while( pptr != NULL && pptr < injson->end) {
		if(isdigit(*pptr) || (*pptr == '-' && pptr == injson->offset)) {
			pptr++;
		}else {
			switch(*pptr) {
				case 'e':
				case 'E':
				case '.':
					isfloat = 1;
				default:
					pptr = NULL;
					break;
			}
		}
	}
	if(isfloat) {
		double value = strtod(injson->offset,&optr);
		if( injson->offset != optr) {
			out = apr_palloc(injson->mpool,sizeof(json_value));
			out->value.dnumber= value;
			out->type  = JSON_DOUBLE;
			injson->offset = optr;
		}
	} else {
		long value = strtol(injson->offset,&optr,10);
		if( injson->offset != optr) {
			out = apr_palloc(injson->mpool,sizeof(json_value));
			out->value.lnumber = value;
			out->type  = JSON_LONG;
			injson->offset = optr;
		}
	}
	return out;
}

json_value * decode_json_null(json_string *injson) {
	json_value *out = NULL;
	if(injson->end - injson->offset > 3 && strncmp(injson->offset,"null",4) == 0) {
		out = apr_palloc(injson->mpool,sizeof(json_value));
		out->type = JSON_NULL;
		injson->offset +=4;
	}
	return out;
}

json_value * decode_json_value(json_string *injson) {
	json_value *outjson= NULL;
	if(injson->jstring ) {
		while(isspace(*(injson->offset)))  injson->offset++;
		switch(*(injson->offset)) {
						case '"':  outjson = decode_json_string(injson); break;
						case '[':  outjson = decode_json_array(injson); break;
						case '{':  outjson = decode_json_object(injson); break;
						case 'n':  outjson = decode_json_null(injson); break;
						case 't':
						case 'f':  outjson = decode_json_boolean(injson); break;
						case '-':
						case '1':
						case '2':
						case '3':
						case '4':
						case '5':
						case '6':
						case '7':
						case '8':
						case '9':
						case '0':  outjson = decode_json_number(injson); break;
						default:
								printf("XError %s\n",injson->jstring); return NULL;
		}
	}//end of if
	return outjson;
}

json_value * decode_json(const char *injson,int injson_size, apr_pool_t *mpool) {
	json_string jstring;
	jstring.jstring = injson;
	jstring.end = injson + injson_size;
	jstring.offset = injson;
	jstring.mpool = mpool;

	json_value *out = decode_json_value(&jstring);

	//chew up trailing ws - and check for crap at the end
	while(jstring.offset < jstring.end && isspace(*(jstring.offset))) jstring.offset++;
	if(jstring.offset != jstring.end ) { out = NULL; }
	return out;
}

void encode_json_array(json_value *json) {
	printf("[");
	int i;
	for(i = 0; i < json->value.array->nelts; i++) {
			if(i > 0) printf(" , ");
			json_value *v = *((json_value**)(json->value.array->elts + (json->value.array->elt_size * i)));
			encode_json(v);
	}
	printf("]");
}

void encode_json_object(json_value *json) {
	printf("{");
	if(json->value.object->node_count) {
                json_skip_node_t *list = json->value.object->node->next_list[0];
                if(list) {
                        do{
				const char *k = (const char*) list->key;
                                json_value *v = (json_value *)list->data;
				json_value key;
				key.type = JSON_STRING;
				key.value.string = (char *)k;
				encode_json_string(&key);
				printf(" : ");
				encode_json(v);
                                list = list->next_list[0];
				if(list) printf(",");
                        }while(list!=NULL);
                }
	}
	printf("}");
}
void encode_json_string(json_value *json) {
	char *p = json->value.string;
	printf("\"");
	while(*p !='\0') {
		switch(*p) {
			case '\n': printf("\\n"); break;
			case '\r': printf("\\r"); break;
			case '\t': printf("\\t"); break;
			case '\b': printf("\\b"); break;
			case '\f': printf("\\f"); break;
			case '\\': printf("\\\\"); break;
			case '/': printf("\\/"); break;
			case '"': printf("\""); break;
			default:
					printf("%c",*p);
		}
		p++;
	}
	printf("\"");
}
void encode_json_number(json_value *json) {
	if(json->type == JSON_LONG) {
		printf("%ld",json->value.lnumber);
	} else {
		printf("%g",json->value.dnumber);
	}
}
void encode_json_boolean(json_value *json) {
	printf("%s",json->value.boolean? "true" : "false");
}
void encode_json_null(json_value *json) {
	printf("null");
}
void encode_json(json_value *json) {
	switch(json->type){
		case JSON_STRING: encode_json_string(json); break;
		case JSON_LONG:
		case JSON_DOUBLE: encode_json_number(json); break;
		case JSON_BOOLEAN: encode_json_boolean(json); break;
		case JSON_NULL: encode_json_null(json); break;
		case JSON_OBJECT: encode_json_object(json); break;
		case JSON_ARRAY: encode_json_array(json); break;
	}
}

#ifdef SIMPLEJSON_MAIN
int main(int argc, char **argv) {
	apr_pool_t *mpool;
	apr_pool_initialize();
	apr_pool_create(&mpool,NULL);
	json_value *out = decode_json(argv[1],mpool);
	if(out) {
		printf("got a value\n");
		encode_json(out);
		printf("\n");
	}
	apr_pool_destroy(mpool);
	apr_pool_terminate();
	return 0;
}
#endif


text:
//
//  FullScreenExample.m
//  FSCalendar
//
//  Created by Wenchao Ding on 9/16/15.
//  Copyright (c) 2015 Wenchao Ding. All rights reserved.
//

#import "FullScreenExampleViewController.h"
#import <EventKit/EventKit.h>
#import "LunarFormatter.h"

#import "FSCalendar.h"

NS_ASSUME_NONNULL_BEGIN

@interface FullScreenExampleViewController()<FSCalendarDataSource,FSCalendarDelegate,FSCalendarDelegateAppearance>

@property (weak, nonatomic) FSCalendar *calendar;

@property (assign, nonatomic) BOOL showsLunar;
@property (assign, nonatomic) BOOL showsEvents;

@property (strong, nonatomic) NSCache *cache;

- (void)todayItemClicked:(id)sender;
- (void)lunarItemClicked:(id)sender;
- (void)eventItemClicked:(id)sender;

@property (strong, nonatomic) NSCalendar *gregorian;
@property (strong, nonatomic) NSDateFormatter *dateFormatter;

@property (strong, nonatomic) NSDate *minimumDate;
@property (strong, nonatomic) NSDate *maximumDate;

@property (strong, nonatomic) LunarFormatter *lunarFormatter;
@property (strong, nonatomic) NSArray<EKEvent *> *events;

- (void)loadCalendarEvents;
- (nullable NSArray<EKEvent *> *)eventsForDate:(NSDate *)date;

@end

NS_ASSUME_NONNULL_END

@implementation FullScreenExampleViewController

#pragma mark - Life cycle

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.title = @"FSCalendar";
        _lunarFormatter = [[LunarFormatter alloc] init];
    }
    return self;
}

- (void)loadView
{
    UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    view.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0];
    self.view = view;

#define FULL_SCREEN 1

#if FULL_SCREEN

    FSCalendar *calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-self.navigationController.navigationBar.frame.size.height)];
    calendar.backgroundColor = [UIColor whiteColor];
    calendar.dataSource = self;
    calendar.delegate = self;
    calendar.pagingEnabled = NO; // important
    calendar.allowsMultipleSelection = YES;
    calendar.firstWeekday = 2;
    calendar.placeholderType = FSCalendarPlaceholderTypeFillHeadTail;
    calendar.appearance.caseOptions = FSCalendarCaseOptionsWeekdayUsesSingleUpperCase|FSCalendarCaseOptionsHeaderUsesUpperCase;
    [self.view addSubview:calendar];
    self.calendar = calendar;

#else

    FSCalendar *calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.size.height, self.view.bounds.size.width, 300)];
    calendar.backgroundColor = [UIColor whiteColor];
    calendar.dataSource = self;
    calendar.delegate = self;
    calendar.allowsMultipleSelection = YES;
    calendar.firstWeekday = 2;
    calendar.appearance.caseOptions = FSCalendarCaseOptionsWeekdayUsesSingleUpperCase|FSCalendarCaseOptionsHeaderUsesUpperCase;
    [self.view addSubview:calendar];
    self.calendar = calendar;

#endif

    UIBarButtonItem *todayItem = [[UIBarButtonItem alloc] initWithTitle:@"Today" style:UIBarButtonItemStylePlain target:self action:@selector(todayItemClicked:)];

    UIBarButtonItem *lunarItem = [[UIBarButtonItem alloc] initWithTitle:@"Lunar" style:UIBarButtonItemStylePlain target:self action:@selector(lunarItemClicked:)];
    [lunarItem setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor magentaColor]} forState:UIControlStateNormal];

    UIBarButtonItem *eventItem = [[UIBarButtonItem alloc] initWithTitle:@"Event" style:UIBarButtonItemStylePlain target:self action:@selector(eventItemClicked:)];
    [eventItem setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor purpleColor]} forState:UIControlStateNormal];

    self.navigationItem.rightBarButtonItems = @[eventItem ,lunarItem, todayItem];

}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

    self.dateFormatter = [[NSDateFormatter alloc] init];
    self.dateFormatter.dateFormat = @"yyyy-MM-dd";

    self.minimumDate = [self.dateFormatter dateFromString:@"2016-02-03"];
    self.maximumDate = [self.dateFormatter dateFromString:@"2021-04-10"];

    self.calendar.accessibilityIdentifier = @"calendar";

    [self loadCalendarEvents];

    /*
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.minimumDate = [self.dateFormatter dateFromString:@"2015-02-01"];
        self.maximumDate = [self.dateFormatter dateFromString:@"2015-06-10"];
        [self.calendar reloadData];
    });
    */
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    [self.cache removeAllObjects];
}

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

#if FULL_SCREEN
    self.calendar.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), self.view.bounds.size.width, self.view.bounds.size.height-CGRectGetMaxY(self.navigationController.navigationBar.frame));
#else
    self.calendar.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), self.view.bounds.size.width, 300);
#endif
}

- (void)dealloc
{
    NSLog(@"%s",__FUNCTION__);
}

#pragma mark - Target actions

- (void)todayItemClicked:(id)sender
{
    [self.calendar setCurrentPage:[NSDate date] animated:YES];
}

- (void)lunarItemClicked:(UIBarButtonItem *)item
{
    self.showsLunar = !self.showsLunar;
    [self.calendar reloadData];
}

- (void)eventItemClicked:(id)sender
{
    self.showsEvents = !self.showsEvents;
    [self.calendar reloadData];
}

#pragma mark - FSCalendarDataSource

- (NSDate *)minimumDateForCalendar:(FSCalendar *)calendar
{
    return self.minimumDate;
}

- (NSDate *)maximumDateForCalendar:(FSCalendar *)calendar
{
    return self.maximumDate;
}

- (NSString *)calendar:(FSCalendar *)calendar subtitleForDate:(NSDate *)date
{
    if (self.showsEvents) {
        EKEvent *event = [self eventsForDate:date].firstObject;
        if (event) {
            return event.title;
        }
    }
    if (self.showsLunar) {
        return [self.lunarFormatter stringFromDate:date];
    }
    return nil;
}

#pragma mark - FSCalendarDelegate

- (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
{
    NSLog(@"did select %@",[self.dateFormatter stringFromDate:date]);
}

- (void)calendarCurrentPageDidChange:(FSCalendar *)calendar
{
    NSLog(@"did change page %@",[self.dateFormatter stringFromDate:calendar.currentPage]);
}

- (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
{
    if (!self.showsEvents) return 0;
    if (!self.events) return 0;
    NSArray<EKEvent *> *events = [self eventsForDate:date];
    return events.count;
}

- (NSArray<UIColor *> *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
{
    if (!self.showsEvents) return nil;
    if (!self.events) return nil;
    NSArray<EKEvent *> *events = [self eventsForDate:date];
    NSMutableArray<UIColor *> *colors = [NSMutableArray arrayWithCapacity:events.count];
    [events enumerateObjectsUsingBlock:^(EKEvent * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [colors addObject:[UIColor colorWithCGColor:obj.calendar.CGColor]];
    }];
    return colors.copy;
}

#pragma mark - Private methods

- (void)loadCalendarEvents
{
    __weak typeof(self) weakSelf = self;
    EKEventStore *store = [[EKEventStore alloc] init];
    [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {

        if(granted) {
            NSDate *startDate = self.minimumDate;
            NSDate *endDate = self.maximumDate;
            NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:startDate endDate:endDate calendars:nil];
            NSArray<EKEvent *> *eventList = [store eventsMatchingPredicate:fetchCalendarEvents];
            NSArray<EKEvent *> *events = [eventList filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable event, NSDictionary<NSString *,id> * _Nullable bindings) {
                return event.calendar.subscribed;
            }]];

            dispatch_async(dispatch_get_main_queue(), ^{
                if (!weakSelf) return;
                weakSelf.events = events;
                [weakSelf.calendar reloadData];
            });

        } else {

            // Alert
            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Permission Error" message:@"Permission of calendar is required for fetching events." preferredStyle:UIAlertControllerStyleAlert];
            [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
            [self presentViewController:alertController animated:YES completion:nil];
        }
    }];

}

- (NSArray<EKEvent *> *)eventsForDate:(NSDate *)date
{
    NSArray<EKEvent *> *events = [self.cache objectForKey:date];
    if ([events isKindOfClass:[NSNull class]]) {
        return nil;
    }
    NSArray<EKEvent *> *filteredEvents = [self.events filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
        return [evaluatedObject.occurrenceDate isEqualToDate:date];
    }]];
    if (filteredEvents.count) {
        [self.cache setObject:filteredEvents forKey:date];
    } else {
        [self.cache setObject:[NSNull null] forKey:date];
    }
    return filteredEvents;
}

@end


text:
import IntersectionObserverWrapper from './IntersectionObserver-wrapper';

/**
 * Lazy load images.
 */
class LazyLoad {

  /**
   * @param {string} querySelector - Valid selector for querySelectorAll.
   * @param {function} callback - callback.
   * @constructor
   */
  constructor(querySelector, callback) {
    const observer = new IntersectionObserverWrapper(this.handleChanges.bind(this), {
      querySelector,
      rootMargin: '100px 0px'
    });

    this._observer = observer.getObserver();
    this.callback = callback;
  }

  /**
   * Handle changes.
   * @param {Array} changes - Array with changes in the intersection of a target element with an ancestor element.
   * @returns {undefined}
   */
  handleChanges(changes) {
    const that = this;

    changes.forEach((change) => {
      if (navigator.onLine === false) {
        return;
      }

      const targetSRC = change.target.getAttribute('data-src');
      const targetSRCSET = change.target.getAttribute('data-srcset');
      const onloadCallback = that.callback;

      change.target.onload = requestAnimationFrame(() => {
        if (onloadCallback) {
          onloadCallback(change.target);
        }
      });

      if (targetSRCSET) {
        change.target.srcset = targetSRCSET;
      }

      change.target.src = targetSRC;
    });
  }
}

export default LazyLoad;