text:
package org.apache.hadoop.hive.metastore;

import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.permission.AclStatus;
import static org.apache.hadoop.fs.permission.AclEntryScope.ACCESS;
import static org.apache.hadoop.fs.permission.AclEntryType.GROUP;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.ReplChangeManager.RecycleType;

import org.apache.hadoop.hive.metastore.api.FieldSchema;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.hadoop.hive.metastore.utils.EncryptionZoneUtils;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.hive.metastore.client.builder.DatabaseBuilder;
import org.apache.hadoop.hive.metastore.client.builder.TableBuilder;
import org.apache.hadoop.hive.metastore.api.Type;
import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
import org.apache.hadoop.hive.metastore.api.InvalidOperationException;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.thrift.TException;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

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

/**
 * TestMetaStoreAuthorization.
 */
public class TestMetaStoreMultipleEncryptionZones {
  private static HiveMetaStoreClient client;
  private static HiveConf hiveConf;
  private static Configuration conf;
  private static Warehouse warehouse;
  private static FileSystem warehouseFs;
  private static MiniDFSCluster miniDFSCluster;
  private static String cmroot;
  private static FileSystem fs;
  private static String cmrootEncrypted;
  private static String jksFile = System.getProperty("java.io.tmpdir") + "/test.jks";
  private static String cmrootFallBack;

  @BeforeClass
  public static void setUp() throws Exception {
    //Create secure cluster
    conf = new Configuration();
    conf.set("hadoop.security.key.provider.path", "jceks://file" + jksFile);
    conf.set("dfs.namenode.acls.enabled", "true");
    miniDFSCluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).format(true).build();
    DFSTestUtil.createKey("test_key_cm", miniDFSCluster, conf);
    DFSTestUtil.createKey("test_key_db", miniDFSCluster, conf);
    hiveConf = new HiveConf(TestReplChangeManager.class);
    hiveConf.setBoolean(HiveConf.ConfVars.REPLCMENABLED.varname, true);
    hiveConf.setInt(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY, 60);
    hiveConf.set(HiveConf.ConfVars.METASTOREWAREHOUSE.varname,
            "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
                    + HiveConf.ConfVars.METASTOREWAREHOUSE.defaultStrVal);

    cmroot = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmroot";
    cmrootFallBack = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmrootFallback";
    cmrootEncrypted = "cmrootEncrypted";
    hiveConf.set(HiveConf.ConfVars.REPLCMDIR.varname, cmroot);
    hiveConf.set(HiveConf.ConfVars.REPLCMENCRYPTEDDIR.varname, cmrootEncrypted);
    hiveConf.set(HiveConf.ConfVars.REPLCMFALLBACKNONENCRYPTEDDIR.varname, cmrootFallBack);
    initReplChangeManager();

    try {
      client = new HiveMetaStoreClient(hiveConf);
    } catch (Throwable e) {
      System.err.println("Unable to open the metastore");
      System.err.println(StringUtils.stringifyException(e));
      throw e;
    }
  }

  private static void initReplChangeManager() throws Exception{
    warehouse = new Warehouse(hiveConf);
    warehouseFs = warehouse.getWhRoot().getFileSystem(hiveConf);
    fs = new Path(cmroot).getFileSystem(hiveConf);
    fs.mkdirs(warehouse.getWhRoot());
  }

  @AfterClass
  public static void tearDown() throws Exception {
    try {
      miniDFSCluster.shutdown();
      client.close();
    } catch (Throwable e) {
      System.err.println("Unable to close metastore");
      System.err.println(StringUtils.stringifyException(e));
      throw e;
    }
  }

  @Test
  public void dropTableWithDifferentEncryptionZonesDifferentKey() throws Throwable {
    String dbName1 = "encrdbdiffkey1";
    String dbName2 = "encrdbdiffkey2";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName1);
    silentDropDatabase(dbName2);
    new DatabaseBuilder()
            .setName(dbName1)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    new DatabaseBuilder()
            .setName(dbName2)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    Path dirDb1 = new Path(warehouse.getWhRoot(), dbName1 +".db");
    warehouseFs.delete(dirDb1, true);
    warehouseFs.mkdirs(dirDb1);
    EncryptionZoneUtils.createEncryptionZone(dirDb1, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb1, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirDb2 = new Path(warehouse.getWhRoot(), dbName2 +".db");
    warehouseFs.delete(dirDb2, true);
    warehouseFs.mkdirs(dirDb2);
    EncryptionZoneUtils.createEncryptionZone(dirDb2, "test_key_cm", conf);
    Path dirTbl2 = new Path(dirDb2, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    new TableBuilder()
            .setDbName(dbName1)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName1, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName2)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName1, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName1, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName2, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName2, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);

  }

  @Test
  public void dropTableWithTableAtEncryptionZoneRoot() throws Throwable {
    String dbName = "encrdbroot";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirTbl2 = new Path(dirDb, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    EncryptionZoneUtils.createEncryptionZone(dirTbl2, "test_key_cm", conf);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    assertTrue(warehouseFs.exists(new Path(dirTbl1, cmrootEncrypted)));
    assertTrue(warehouseFs.exists(new Path(dirTbl2, cmrootEncrypted)));
  }

  @Test
  public void dropTableWithDifferentEncryptionZonesSameKey() throws Throwable {
    String dbName1 = "encrdbsamekey1";
    String dbName2 = "encrdbsamekey2";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName1);
    silentDropDatabase(dbName2);
    new DatabaseBuilder()
            .setName(dbName1)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    new DatabaseBuilder()
            .setName(dbName2)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    Path dirDb1 = new Path(warehouse.getWhRoot(), dbName1 +".db");
    warehouseFs.mkdirs(dirDb1);
    EncryptionZoneUtils.createEncryptionZone(dirDb1, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb1, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirDb2 = new Path(warehouse.getWhRoot(), dbName2 +".db");
    warehouseFs.mkdirs(dirDb2);
    EncryptionZoneUtils.createEncryptionZone(dirDb2, "test_key_db", conf);
    Path dirTbl2 = new Path(dirDb2, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    new TableBuilder()
            .setDbName(dbName1)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName1, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName2)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName1, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName1, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName2, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName2, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);

  }

  @Test
  public void dropTableWithSameEncryptionZones() throws Throwable {
    String dbName = "encrdb3";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";
    silentDropDatabase(dbName);

    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.delete(dirDb, true);
    warehouseFs.mkdirs(dirDb);
    EncryptionZoneUtils.createEncryptionZone(dirDb, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirTbl2 = new Path(dirDb, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
  }

  @Test
  public void dropTableWithoutEncryptionZonesForCm() throws Throwable {
    String dbName = "simpdb1";
    String tblName = "simptbl";
    String typeName = "Person";
    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName);
    Assert.assertNotNull(tbl);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, tblName);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName);
    } catch (Exception e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
  }

  @Test
  public void dropExternalTableWithSameEncryptionZonesForCm() throws Throwable {
    String dbName = "encrdb4";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";
    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.delete(dirDb, true);
    warehouseFs.mkdirs(dirDb);
    EncryptionZoneUtils.createEncryptionZone(dirDb, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirTbl2 = new Path(dirDb, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
  }

  @Test
  public void dropExternalTableWithDifferentEncryptionZones() throws Throwable {
    String dbName = "encrdb5";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirTbl2 = new Path(dirDb, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    EncryptionZoneUtils.createEncryptionZone(dirTbl2, "test_key_db", conf);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
  }

  @Test
  public void dropExternalTableWithDifferentEncryptionZonesDifferentKey() throws Throwable {
    String dbName = "encrdb6";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirTbl2 = new Path(dirDb, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    EncryptionZoneUtils.createEncryptionZone(dirTbl2, "test_key_cm", conf);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName1);
    } catch (MetaException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName2);
    } catch (MetaException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
  }

  @Test
  public void dropExternalTableWithoutEncryptionZonesForCm() throws Throwable {
    String dbName = "simpdb2";
    String tblName = "simptbl";
    String typeName = "Person";
    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addTableParam("EXTERNAL", "true")
            .addTableParam("external.table.purge", "true")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName);
    Assert.assertNotNull(tbl);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, tblName);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    boolean exceptionThrown = false;
    try {
      client.dropTable(dbName, tblName);
    } catch (Exception e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
  }

  @Test
  public void truncateTableWithDifferentEncryptionZones() throws Throwable {
    String dbName1 = "encrdbtrunc1";
    String dbName2 = "encrdbtrunc2";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName1);
    silentDropDatabase(dbName2);
    new DatabaseBuilder()
            .setName(dbName1)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    new DatabaseBuilder()
            .setName(dbName2)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    Path dirDb1 = new Path(warehouse.getWhRoot(), dbName1 +".db");
    warehouseFs.delete(dirDb1, true);
    warehouseFs.mkdirs(dirDb1);
    EncryptionZoneUtils.createEncryptionZone(dirDb1, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb1, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirDb2 = new Path(warehouse.getWhRoot(), dbName2 +".db");
    warehouseFs.delete(dirDb2, true);
    warehouseFs.mkdirs(dirDb2);
    EncryptionZoneUtils.createEncryptionZone(dirDb2, "test_key_db", conf);
    Path dirTbl2 = new Path(dirDb2, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    new TableBuilder()
            .setDbName(dbName1)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName1, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName2)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    boolean exceptionThrown = false;
    try {
      client.truncateTable(dbName1, tblName1, null);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    assertNotNull(client.getTable(dbName1, tblName1));
    exceptionThrown = false;
    try {
      client.truncateTable(dbName2, tblName2, null);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    assertNotNull(client.getTable(dbName2, tblName2));
  }

  @Test
  public void truncateTableWithDifferentEncryptionZonesDifferentKey() throws Throwable {
    String dbName1 = "encrdb1";
    String dbName2 = "encrdb2";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";

    silentDropDatabase(dbName1);
    silentDropDatabase(dbName2);
    new DatabaseBuilder()
            .setName(dbName1)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    new DatabaseBuilder()
            .setName(dbName2)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    Path dirDb1 = new Path(warehouse.getWhRoot(), dbName1 +".db");
    warehouseFs.mkdirs(dirDb1);
    EncryptionZoneUtils.createEncryptionZone(dirDb1, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb1, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirDb2 = new Path(warehouse.getWhRoot(), dbName2 +".db");
    warehouseFs.mkdirs(dirDb2);
    EncryptionZoneUtils.createEncryptionZone(dirDb2, "test_key_db", conf);
    Path dirTbl2 = new Path(dirDb2, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    new TableBuilder()
            .setDbName(dbName1)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName1, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName2)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    boolean exceptionThrown = false;
    try {
      client.truncateTable(dbName1, tblName1, null);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    assertNotNull(client.getTable(dbName1, tblName1));
    exceptionThrown = false;
    try {
      client.truncateTable(dbName2, tblName2, null);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    assertNotNull(client.getTable(dbName2, tblName2));
  }

  @Test
  public void truncateTableWithSameEncryptionZones() throws Throwable {
    String dbName = "encrdb9";
    String tblName1 = "encrtbl1";
    String tblName2 = "encrtbl2";
    String typeName = "Person";
    client.dropTable(dbName, tblName1);
    client.dropTable(dbName, tblName2);
    silentDropDatabase(dbName);
    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName1)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl = client.getTable(dbName, tblName1);
    Assert.assertNotNull(tbl);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName2)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.delete(dirDb, true);
    warehouseFs.mkdirs(dirDb);
    EncryptionZoneUtils.createEncryptionZone(dirDb, "test_key_db", conf);
    Path dirTbl1 = new Path(dirDb, tblName1);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    Path dirTbl2 = new Path(dirDb, tblName2);
    warehouseFs.mkdirs(dirTbl2);
    Path part12 = new Path(dirTbl2, "part1");
    createFile(part12, "testClearer12");

    boolean exceptionThrown = false;
    try {
      client.truncateTable(dbName, tblName1, null);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName1);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);

    try {
      client.truncateTable(dbName, tblName2, null);
    } catch (MetaException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part12));
    try {
      client.getTable(dbName, tblName2);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
  }

  @Test
  public void truncateTableWithoutEncryptionZonesForCm() throws Throwable {
    String dbName = "simpdb3";
    String tblName = "simptbl";
    String typeName = "Person";
    client.dropTable(dbName, tblName);
    silentDropDatabase(dbName);

    new DatabaseBuilder()
            .setName(dbName)
            .addParam("repl.source.for", "1, 2, 3")
            .create(client, hiveConf);

    client.dropType(typeName);
    Type typ1 = new Type();
    typ1.setName(typeName);
    typ1.setFields(new ArrayList<>(2));
    typ1.getFields().add(
            new FieldSchema("name", ColumnType.STRING_TYPE_NAME, ""));
    typ1.getFields().add(
            new FieldSchema("income", ColumnType.INT_TYPE_NAME, ""));
    client.createType(typ1);

    new TableBuilder()
            .setDbName(dbName)
            .setTableName(tblName)
            .setCols(typ1.getFields())
            .setNumBuckets(1)
            .addBucketCol("name")
            .addStorageDescriptorParam("test_param_1", "Use this for comments etc")
            .create(client, hiveConf);

    Table tbl2 = client.getTable(dbName, tblName);
    Assert.assertNotNull(tbl2);

    Path dirDb = new Path(warehouse.getWhRoot(), dbName +".db");
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, tblName);
    warehouseFs.mkdirs(dirTbl1);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    boolean exceptionThrown = false;
    try {
      client.truncateTable(dbName, tblName, null);
    } catch (Exception e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    assertFalse(warehouseFs.exists(part11));
    try {
      client.getTable(dbName, tblName);
    } catch (NoSuchObjectException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
  }

  @Test
  public void recycleFailureWithDifferentEncryptionZonesForCm() throws Throwable {
    Path dirDb = new Path(warehouse.getWhRoot(), "db2");
    warehouseFs.delete(dirDb, true);
    warehouseFs.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, "tbl1");
    warehouseFs.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    boolean exceptionThrown = false;
    try {
      ReplChangeManager.getInstance(hiveConf).recycle(dirTbl1, RecycleType.MOVE, false);
    } catch (RemoteException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);
  }

  @Test
  public void testClearerEncrypted() throws Exception {
    HiveConf hiveConfCmClearer = new HiveConf(TestReplChangeManager.class);
    hiveConfCmClearer.setBoolean(HiveConf.ConfVars.REPLCMENABLED.varname, true);
    hiveConfCmClearer.setInt(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY, 60);
    hiveConfCmClearer.set(HiveConf.ConfVars.METASTOREWAREHOUSE.varname,
            "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
                    + HiveConf.ConfVars.METASTOREWAREHOUSE.defaultStrVal);

    String cmrootCmClearer = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmrootClearer";
    hiveConfCmClearer.set(HiveConf.ConfVars.REPLCMDIR.varname, cmrootCmClearer);
    Warehouse warehouseCmClearer = new Warehouse(hiveConfCmClearer);
    FileSystem cmfs = new Path(cmrootCmClearer).getFileSystem(hiveConfCmClearer);
    cmfs.mkdirs(warehouseCmClearer.getWhRoot());

    FileSystem fsWarehouse = warehouseCmClearer.getWhRoot().getFileSystem(hiveConfCmClearer);
    long now = System.currentTimeMillis();
    Path dirDb = new Path(warehouseCmClearer.getWhRoot(), "db1");
    fsWarehouse.delete(dirDb, true);
    fsWarehouse.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, "tbl1");
    fsWarehouse.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");
    String fileChksum11 = ReplChangeManager.checksumFor(part11, fsWarehouse);
    Path part12 = new Path(dirTbl1, "part2");
    createFile(part12, "testClearer12");
    String fileChksum12 = ReplChangeManager.checksumFor(part12, fsWarehouse);
    Path dirTbl2 = new Path(dirDb, "tbl2");
    fsWarehouse.mkdirs(dirTbl2);
    EncryptionZoneUtils.createEncryptionZone(dirTbl2, "test_key_db", conf);
    Path part21 = new Path(dirTbl2, "part1");
    createFile(part21, "testClearer21");
    String fileChksum21 = ReplChangeManager.checksumFor(part21, fsWarehouse);
    Path part22 = new Path(dirTbl2, "part2");
    createFile(part22, "testClearer22");
    String fileChksum22 = ReplChangeManager.checksumFor(part22, fsWarehouse);
    Path dirTbl3 = new Path(dirDb, "tbl3");
    fsWarehouse.mkdirs(dirTbl3);
    EncryptionZoneUtils.createEncryptionZone(dirTbl3, "test_key_cm", conf);
    Path part31 = new Path(dirTbl3, "part1");
    createFile(part31, "testClearer31");
    String fileChksum31 = ReplChangeManager.checksumFor(part31, fsWarehouse);
    Path part32 = new Path(dirTbl3, "part2");
    createFile(part32, "testClearer32");
    String fileChksum32 = ReplChangeManager.checksumFor(part32, fsWarehouse);

    ReplChangeManager.getInstance(hiveConfCmClearer).recycle(dirTbl1, RecycleType.MOVE, false);
    ReplChangeManager.getInstance(hiveConfCmClearer).recycle(dirTbl2, RecycleType.MOVE, false);
    ReplChangeManager.getInstance(hiveConfCmClearer).recycle(dirTbl3, RecycleType.MOVE, true);

    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part11.getName(), fileChksum11,
            ReplChangeManager.getInstance(conf).getCmRoot(part11).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part12.getName(), fileChksum12,
            ReplChangeManager.getInstance(conf).getCmRoot(part12).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part21.getName(), fileChksum21,
            ReplChangeManager.getInstance(conf).getCmRoot(part21).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part22.getName(), fileChksum22,
            ReplChangeManager.getInstance(conf).getCmRoot(part22).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part31.getName(), fileChksum31,
            ReplChangeManager.getInstance(conf).getCmRoot(part31).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part32.getName(), fileChksum32,
            ReplChangeManager.getInstance(conf).getCmRoot(part32).toString())));

    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfCmClearer, part11.getName(), fileChksum11,
            ReplChangeManager.getInstance(conf).getCmRoot(part11).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);
    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfCmClearer, part21.getName(), fileChksum21,
            ReplChangeManager.getInstance(conf).getCmRoot(part21).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);
    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfCmClearer, part31.getName(), fileChksum31,
            ReplChangeManager.getInstance(conf).getCmRoot(part31).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);
    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfCmClearer, part32.getName(), fileChksum32,
            ReplChangeManager.getInstance(conf).getCmRoot(part32).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);

    ReplChangeManager.scheduleCMClearer(hiveConfCmClearer);

    long start = System.currentTimeMillis();
    long end;
    boolean cleared = false;
    do {
      Thread.sleep(200);
      end = System.currentTimeMillis();
      if (end - start > 5000) {
        Assert.fail("timeout, cmroot has not been cleared");
      }
      if (!fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part11.getName(), fileChksum11,
              ReplChangeManager.getInstance(conf).getCmRoot(part11).toString())) &&
              fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part12.getName(), fileChksum12,
                      ReplChangeManager.getInstance(conf).getCmRoot(part12).toString())) &&
              !fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part21.getName(), fileChksum21,
                      ReplChangeManager.getInstance(conf).getCmRoot(part21).toString())) &&
              fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part22.getName(), fileChksum22,
                      ReplChangeManager.getInstance(conf).getCmRoot(part22).toString())) &&
              !fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part31.getName(), fileChksum31,
                      ReplChangeManager.getInstance(conf).getCmRoot(part31).toString())) &&
              !fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfCmClearer, part32.getName(), fileChksum32,
                      ReplChangeManager.getInstance(conf).getCmRoot(part32).toString()))) {
        cleared = true;
      }
    } while (!cleared);
  }

  @Test
  public void testCmRootAclPermissions() throws Exception {
    HiveConf hiveConfAclPermissions = new HiveConf(TestReplChangeManager.class);
    hiveConfAclPermissions.setBoolean(HiveConf.ConfVars.REPLCMENABLED.varname, true);
    hiveConfAclPermissions.setInt(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY, 60);
    hiveConfAclPermissions.set(HiveConf.ConfVars.METASTOREWAREHOUSE.varname,
            "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
                    + HiveConf.ConfVars.METASTOREWAREHOUSE.defaultStrVal);

    String cmRootAclPermissions = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmRootAclPermissions";
    hiveConfAclPermissions.set(HiveConf.ConfVars.REPLCMDIR.varname, cmRootAclPermissions);
    Warehouse warehouseCmPermissions = new Warehouse(hiveConfAclPermissions);
    FileSystem cmfs = new Path(cmRootAclPermissions).getFileSystem(hiveConfAclPermissions);
    cmfs.mkdirs(warehouseCmPermissions.getWhRoot());

    FileSystem fsWarehouse = warehouseCmPermissions.getWhRoot().getFileSystem(hiveConfAclPermissions);
    //change the group of warehouse for testing
    Path warehouse = new Path(hiveConfAclPermissions.get(HiveConf.ConfVars.METASTOREWAREHOUSE.varname));
    fsWarehouse.setOwner(warehouse, null, "testgroup");

    long now = System.currentTimeMillis();
    Path dirDb = new Path(warehouseCmPermissions.getWhRoot(), "db_perm");
    fsWarehouse.delete(dirDb, true);
    fsWarehouse.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, "tbl1");
    fsWarehouse.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");
    String fileChksum11 = ReplChangeManager.checksumFor(part11, fsWarehouse);
    Path part12 = new Path(dirTbl1, "part2");
    createFile(part12, "testClearer12");
    String fileChksum12 = ReplChangeManager.checksumFor(part12, fsWarehouse);
    Path dirTbl2 = new Path(dirDb, "tbl2");
    fsWarehouse.mkdirs(dirTbl2);
    EncryptionZoneUtils.createEncryptionZone(dirTbl2, "test_key_db", conf);
    Path part21 = new Path(dirTbl2, "part1");
    createFile(part21, "testClearer21");
    String fileChksum21 = ReplChangeManager.checksumFor(part21, fsWarehouse);
    Path part22 = new Path(dirTbl2, "part2");
    createFile(part22, "testClearer22");
    String fileChksum22 = ReplChangeManager.checksumFor(part22, fsWarehouse);
    Path dirTbl3 = new Path(dirDb, "tbl3");
    fsWarehouse.mkdirs(dirTbl3);
    EncryptionZoneUtils.createEncryptionZone(dirTbl3, "test_key_cm", conf);
    Path part31 = new Path(dirTbl3, "part1");
    createFile(part31, "testClearer31");
    String fileChksum31 = ReplChangeManager.checksumFor(part31, fsWarehouse);
    Path part32 = new Path(dirTbl3, "part2");
    createFile(part32, "testClearer32");
    String fileChksum32 = ReplChangeManager.checksumFor(part32, fsWarehouse);

    final UserGroupInformation proxyUserUgi =
            UserGroupInformation.createUserForTesting("impala", new String[] {"testgroup"});

    fsWarehouse.setOwner(dirDb, "impala", "default");
    fsWarehouse.setOwner(dirTbl1, "impala", "default");
    fsWarehouse.setOwner(dirTbl2, "impala", "default");
    fsWarehouse.setOwner(dirTbl3, "impala", "default");
    fsWarehouse.setOwner(part11, "impala", "default");
    fsWarehouse.setOwner(part12, "impala", "default");
    fsWarehouse.setOwner(part21, "impala", "default");
    fsWarehouse.setOwner(part22, "impala", "default");
    fsWarehouse.setOwner(part31, "impala", "default");
    fsWarehouse.setOwner(part32, "impala", "default");

    proxyUserUgi.doAs((PrivilegedExceptionAction<Void>) () -> {
      try {
        //impala doesn't have access but it belongs to a group which has access through acl.
        ReplChangeManager.getInstance(hiveConfAclPermissions).recycle(dirTbl1, RecycleType.MOVE, false);
        ReplChangeManager.getInstance(hiveConfAclPermissions).recycle(dirTbl2, RecycleType.MOVE, false);
        ReplChangeManager.getInstance(hiveConfAclPermissions).recycle(dirTbl3, RecycleType.MOVE, true);
      } catch (Exception e) {
        Assert.fail();
      }
      return null;
    });

    String cmEncrypted = hiveConf.get(HiveConf.ConfVars.REPLCMENCRYPTEDDIR.varname, cmrootEncrypted);
    AclStatus aclStatus = fsWarehouse.getAclStatus(new Path(dirTbl1 + Path.SEPARATOR + cmEncrypted));
    AclStatus aclStatus2 = fsWarehouse.getAclStatus(new Path(dirTbl2 + Path.SEPARATOR + cmEncrypted));
    AclStatus aclStatus3 = fsWarehouse.getAclStatus(new Path(dirTbl3 + Path.SEPARATOR + cmEncrypted));
    AclEntry expectedAcl = new AclEntry.Builder().setScope(ACCESS).setType(GROUP).setName("testgroup").
            setPermission(fsWarehouse.getFileStatus(warehouse).getPermission().getGroupAction()).build();
    Assert.assertTrue(aclStatus.getEntries().contains(expectedAcl));
    Assert.assertTrue(aclStatus2.getEntries().contains(expectedAcl));
    Assert.assertTrue(aclStatus3.getEntries().contains(expectedAcl));

    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part11.getName(), fileChksum11,
            ReplChangeManager.getInstance(conf).getCmRoot(part11).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part12.getName(), fileChksum12,
            ReplChangeManager.getInstance(conf).getCmRoot(part12).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part21.getName(), fileChksum21,
            ReplChangeManager.getInstance(conf).getCmRoot(part21).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part22.getName(), fileChksum22,
            ReplChangeManager.getInstance(conf).getCmRoot(part22).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part31.getName(), fileChksum31,
            ReplChangeManager.getInstance(conf).getCmRoot(part31).toString())));
    assertTrue(fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part32.getName(), fileChksum32,
            ReplChangeManager.getInstance(conf).getCmRoot(part32).toString())));

    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfAclPermissions, part11.getName(), fileChksum11,
            ReplChangeManager.getInstance(conf).getCmRoot(part11).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);
    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfAclPermissions, part21.getName(), fileChksum21,
            ReplChangeManager.getInstance(conf).getCmRoot(part21).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);
    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfAclPermissions, part31.getName(), fileChksum31,
            ReplChangeManager.getInstance(conf).getCmRoot(part31).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);
    fsWarehouse.setTimes(ReplChangeManager.getCMPath(hiveConfAclPermissions, part32.getName(), fileChksum32,
            ReplChangeManager.getInstance(conf).getCmRoot(part32).toString()),
            now - 7 * 86400 * 1000 * 2, now - 7 * 86400 * 1000 * 2);

    ReplChangeManager.scheduleCMClearer(hiveConfAclPermissions);

    long start = System.currentTimeMillis();
    long end;
    boolean cleared = false;
    do {
      Thread.sleep(200);
      end = System.currentTimeMillis();
      if (end - start > 5000) {
        Assert.fail("timeout, cmroot has not been cleared");
      }
      if (!fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part11.getName(), fileChksum11,
              ReplChangeManager.getInstance(conf).getCmRoot(part11).toString())) &&
              fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part12.getName(), fileChksum12,
                      ReplChangeManager.getInstance(conf).getCmRoot(part12).toString())) &&
              !fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part21.getName(), fileChksum21,
                      ReplChangeManager.getInstance(conf).getCmRoot(part21).toString())) &&
              fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part22.getName(), fileChksum22,
                      ReplChangeManager.getInstance(conf).getCmRoot(part22).toString())) &&
              !fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part31.getName(), fileChksum31,
                      ReplChangeManager.getInstance(conf).getCmRoot(part31).toString())) &&
              !fsWarehouse.exists(ReplChangeManager.getCMPath(hiveConfAclPermissions, part32.getName(), fileChksum32,
                      ReplChangeManager.getInstance(conf).getCmRoot(part32).toString()))) {
        cleared = true;
      }
    } while (!cleared);
  }

  @Test
  public void testCmrootEncrypted() throws Exception {
    HiveConf encryptedHiveConf = new HiveConf(TestReplChangeManager.class);
    encryptedHiveConf.setBoolean(HiveConf.ConfVars.REPLCMENABLED.varname, true);
    encryptedHiveConf.setInt(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY, 60);
    encryptedHiveConf.set(HiveConf.ConfVars.METASTOREWAREHOUSE.varname,
            "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
                    + HiveConf.ConfVars.METASTOREWAREHOUSE.defaultStrVal);

    String cmrootdirEncrypted = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmrootDirEncrypted";
    encryptedHiveConf.set(HiveConf.ConfVars.REPLCMDIR.varname, cmrootdirEncrypted);
    FileSystem cmrootdirEncryptedFs = new Path(cmrootdirEncrypted).getFileSystem(hiveConf);
    cmrootdirEncryptedFs.mkdirs(new Path(cmrootdirEncrypted));
    encryptedHiveConf.set(HiveConf.ConfVars.REPLCMFALLBACKNONENCRYPTEDDIR.varname, cmrootFallBack);

    //Create cm in encrypted zone
    EncryptionZoneUtils.createEncryptionZone(new Path(cmrootdirEncrypted), "test_key_db", conf);
    ReplChangeManager.resetReplChangeManagerInstance();
    Warehouse warehouseEncrypted = new Warehouse(encryptedHiveConf);
    FileSystem warehouseFsEncrypted = warehouseEncrypted.getWhRoot().getFileSystem(encryptedHiveConf);
    FileSystem fsCmEncrypted = new Path(cmrootdirEncrypted).getFileSystem(encryptedHiveConf);
    fsCmEncrypted.mkdirs(warehouseEncrypted.getWhRoot());

    Path dirDb = new Path(warehouseEncrypted.getWhRoot(), "db3");
    warehouseFsEncrypted.delete(dirDb, true);
    warehouseFsEncrypted.mkdirs(dirDb);
    Path dirTbl1 = new Path(dirDb, "tbl1");
    warehouseFsEncrypted.mkdirs(dirTbl1);
    EncryptionZoneUtils.createEncryptionZone(dirTbl1, "test_key_db", conf);
    Path part11 = new Path(dirTbl1, "part1");
    createFile(part11, "testClearer11");

    boolean exceptionThrown = false;
    try {
      ReplChangeManager.getInstance(encryptedHiveConf).recycle(dirTbl1, RecycleType.MOVE, false);
    } catch (RemoteException e) {
      exceptionThrown = true;
      assertTrue(e.getMessage().contains("can't be moved from encryption zone"));
    }
    assertFalse(exceptionThrown);

    Path dirDbUnEncrypted = new Path(warehouseEncrypted.getWhRoot(), "db3en");
    warehouseFsEncrypted.delete(dirDbUnEncrypted, true);
    warehouseFsEncrypted.mkdirs(dirDbUnEncrypted);
    Path dirTblun1 = new Path(dirDbUnEncrypted, "tbl1");
    warehouseFsEncrypted.mkdirs(dirTblun1);
    Path partun11 = new Path(dirTblun1, "part1");
    createFile(partun11, "testClearer11");

    exceptionThrown = false;
    try {
      ReplChangeManager.getInstance(encryptedHiveConf).recycle(dirDbUnEncrypted, RecycleType.MOVE, false);
    } catch (IOException e) {
      exceptionThrown = true;
    }
    assertFalse(exceptionThrown);
    cmrootdirEncryptedFs.delete(new Path(cmrootdirEncrypted), true);
    ReplChangeManager.resetReplChangeManagerInstance();
    initReplChangeManager();
  }

  @Test
  public void testCmrootFallbackEncrypted() throws Exception {
    HiveConf encryptedHiveConf = new HiveConf(TestReplChangeManager.class);
    encryptedHiveConf.setBoolean(HiveConf.ConfVars.REPLCMENABLED.varname, true);
    encryptedHiveConf.setInt(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY, 60);
    encryptedHiveConf.set(HiveConf.ConfVars.METASTOREWAREHOUSE.varname,
            "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
                    + HiveConf.ConfVars.METASTOREWAREHOUSE.defaultStrVal);
    String cmrootdirEncrypted = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmrootIsEncrypted";
    String cmRootFallbackEncrypted = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
            + "/cmrootFallbackEncrypted";
    FileSystem cmrootdirEncryptedFs = new Path(cmrootdirEncrypted).getFileSystem(encryptedHiveConf);
    try {
      cmrootdirEncryptedFs.mkdirs(new Path(cmrootdirEncrypted));
      cmrootdirEncryptedFs.mkdirs(new Path(cmRootFallbackEncrypted));
      encryptedHiveConf.set(HiveConf.ConfVars.REPLCMDIR.varname, cmrootdirEncrypted);
      encryptedHiveConf.set(HiveConf.ConfVars.REPLCMFALLBACKNONENCRYPTEDDIR.varname, cmRootFallbackEncrypted);

      //Create cm in encrypted zone
      EncryptionZoneUtils.createEncryptionZone(new Path(cmrootdirEncrypted), "test_key_db", conf);
      EncryptionZoneUtils.createEncryptionZone(new Path(cmRootFallbackEncrypted), "test_key_db", conf);
      ReplChangeManager.resetReplChangeManagerInstance();
      boolean exceptionThrown = false;
      try {
        new Warehouse(encryptedHiveConf);
      } catch (MetaException e) {
        exceptionThrown = true;
        assertTrue(e.getMessage().contains("should not be encrypted"));
      }
      assertTrue(exceptionThrown);
    } finally {
      cmrootdirEncryptedFs.delete(new Path(cmrootdirEncrypted), true);
      cmrootdirEncryptedFs.delete(new Path(cmRootFallbackEncrypted), true);
      ReplChangeManager.resetReplChangeManagerInstance();
      initReplChangeManager();
    }
  }

  @Test
  public void testCmrootFallbackRelative() throws Exception {
    HiveConf encryptedHiveConf = new HiveConf(TestReplChangeManager.class);
    encryptedHiveConf.setBoolean(HiveConf.ConfVars.REPLCMENABLED.varname, true);
    encryptedHiveConf.setInt(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY, 60);
    encryptedHiveConf.set(HiveConf.ConfVars.METASTOREWAREHOUSE.varname,
            "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort()
                    + HiveConf.ConfVars.METASTOREWAREHOUSE.defaultStrVal);
    String cmrootdirEncrypted = "hdfs://" + miniDFSCluster.getNameNode().getHostAndPort() + "/cmrootIsEncrypted";
    String cmRootFallbackEncrypted = "cmrootFallbackEncrypted";
    FileSystem cmrootdirEncryptedFs = new Path(cmrootdirEncrypted).getFileSystem(encryptedHiveConf);
    try {
      cmrootdirEncryptedFs.mkdirs(new Path(cmrootdirEncrypted));
      cmrootdirEncryptedFs.mkdirs(new Path(cmRootFallbackEncrypted));
      encryptedHiveConf.set(HiveConf.ConfVars.REPLCMDIR.varname, cmrootdirEncrypted);
      encryptedHiveConf.set(HiveConf.ConfVars.REPLCMFALLBACKNONENCRYPTEDDIR.varname, cmRootFallbackEncrypted);

      //Create cm in encrypted zone
      EncryptionZoneUtils.createEncryptionZone(new Path(cmrootdirEncrypted), "test_key_db", conf);

      ReplChangeManager.resetReplChangeManagerInstance();
      boolean exceptionThrown = false;
      try {
        new Warehouse(encryptedHiveConf);
      } catch (MetaException e) {
        exceptionThrown = true;
        assertTrue(e.getMessage().contains("should be absolute"));
      }
      assertTrue(exceptionThrown);
    } finally {
      cmrootdirEncryptedFs.delete(new Path(cmrootdirEncrypted), true);
      cmrootdirEncryptedFs.delete(new Path(cmRootFallbackEncrypted), true);
      ReplChangeManager.resetReplChangeManagerInstance();
      initReplChangeManager();
    }
  }

  private void createFile(Path path, String content) throws IOException {
    FSDataOutputStream output = path.getFileSystem(hiveConf).create(path);
    output.writeChars(content);
    output.close();
  }

  private void silentDropDatabase(String dbName) throws TException {
    try {
      for (String tableName : client.getTables(dbName, "*")) {
        client.dropTable(dbName, tableName);
      }
      client.dropDatabase(dbName);
    } catch (NoSuchObjectException|InvalidOperationException|MetaException e) {
      // NOP
    }
  }
}

redpajama_set_name: RedPajamaGithub


text:
WATCH: Having raised over R50m SweepSouth's Aisha Pandor gives her tips to success
Entrepreneurs / 1 November 2019, 07:00am / BR Correspondent
Aisha Pandor's SweepSouth has created more than 15 000 employment opportunities for previously unemployed or underemployed domestic workers. Photo: Supplied
JOHANNESBURG – Having recently reached a milestone of being in operation for five years, raising more than R50 million in their latest funding round, while most importantly having created more than 15 000 employment opportunities for previously unemployed or underemployed domestic workers, it cannot be denied that domestic cleaning services app, SweepSouth is a South African startup success story.
While the company looks towards its future with plans to expand into new markets and offer services beyond domestic services like handymen, plumbers, electricians, locksmiths, carpet cleaners, and nannies, as well as the growing its online SweepSouth Shop which sells a range of home products, SweepSouth's co-founder and CEO Aisha Pandor took a moment to look back and give her tips on personal and business success.
Find Unique Problems
When setting out in business, particularly if you're going to be striking it out on your own as an entrepreneur, think big. Focus on unique challenges and solutions that have the potential to change people's lives. In South Africa, these are a plenty. Through technology, SweepSouth was able to address a core consumer issue – struggling to find reliable & vetted domestic help at decent rates that are also affordable. But it has done so while also addressing unemployment and underemployment, and domestic worker wage issues.
Define Success For Yourself
"When you have a big vision, you cannot expect to reach your outcomes on day one," says Aisha. Success is not a destination, and it is natural for goal posts to shift. There is no such thing as overnight success, and every stage of development comes with some frustration. "The practical details of whatever you set out to achieve could mean you have to redefine what success looks like at every stage. Set smaller, more attainable goals along the way to keep you on track."
Social Problems Can Be Business Opportunities
According to Aisha, the interesting thing about growing a business in South Africa is that you have to be creative and a problem solver. "It may sometimes be something outside of your business focus or something you have to fix before you can grow to the next level. There are amazing opportunities to unearth solutions to social problems while yo buuild your business."
Lean On & Learn From Your Networks
"Learn how to work with people, how to lead people and how to get people to buy in to your vision. Never underestimate word of mouth and feedback to improve and build trust. In your business and in life, you don't need to go it alone," says Aisha. "There are people who have done it before. Ask for advice, broaden your networks and share your challenges with a trusted person. When you don't, it can be damaging to you, your business and the people who trust you to lead them.
Pick Your Partners Carefully
"It is your vision, and you need to think carefully about the partners and investors you bring on-board. Your partners should have a similar vision as you, but skill sets that complement yours," adds Aisha. "When you exclusively self-fund a business, it can take longer to get to the same stage as a business with investors. So, the right investors can be good for business. When closing an investment, people often underestimate how long it takes to conclude an agreement, so you also have to make sure you have enough runway to allow that process to unfold."
Remember You Are Not Your Business
Aisha believes the notion of balance is a fallacy. "I always just try to do the best I can," she says. For Aisha, burnout is also real and it is something that can always be close if you do not learn to redefine what success is to you. It is important to de-couple business success from your personal life. Personal success is about reaching other goals, and about how you feel about yourself. Separating personal and business success means you still set work goals, but you can feel good about yourself whether or not the business works out in the end.
Free Market Economy
Win a R500 voucher from SweepSouth
The woman behind one of SA's biggest startups
OPINION: How technology can bring people together
GALLERY: Celebrities who have invested in startups
Female entrepreneurs honoured for achievements
Domestic worker app wins SAVCA award
SweepSouth raises over R50m in new investment creating 15 000 job opportunities

redpajama_set_name: RedPajamaCommonCrawl


I have long said that authors are not paid for their words, they are paid for their perseverance. When it's easy to give up, good writers stick with it, improve their craft, and overcome that stack of rejections.
If that doesn't sound long enough, this is where the story gets truly bizarre — and shows that a lot of patience (and a little perseverance) pays off.
I sent the manuscript to Sterling Publishing in late 2012, a few months before Barnes and Noble, which owns Sterling, announced they were selling the company. Sterling quickly said they were no longer acquiring manuscripts, and just like that, my book was out of the running. At least it hadn't been rejected!
A few months later, Barnes and Noble announced it was pulling Sterling off the market. I waited a few months before writing Sterling to see if anyone read my story.
I received no response and decided to let it go.
A year and a half later, I get an email out of the blue from Executive Editor Meredith Mundy at Sterling. She said she loved the story, had taken it up through all the proper channels, and wanted to buy it.
I sold my first picture book!
So where was the manuscript all that time?
Well, funny story. When Sterling went up for sale, all unread manuscripts were tucked away in boxes. Many of those boxes, it seems, were forgotten (hey, editors are busy enough trying to read new manuscripts, let alone old ones). Nearly two years later, Sterling moved into new offices on the Avenue of the Americas, where those boxes were discovered. Meredith, to her credit, didn't ignore them — she actually dove in and read them. And voila! My manuscript passed the test.
So, that's it. The story is all of 500 words, meaning my advance is not really paying me for my words, it's paying me for my perseverance. It's paying me for not giving up, even when I wanted to. It took a lot of hard work and a lot of patience, but it paid off.
Now, to send her my next manuscript!
Leaping Lemmings!, illustrated by Nicola Slater, will be published in the fall of 2016.
Great story John. It is inspirational to those of us who sometimes are impatient and expect immediate results. I hope you enjoy the success and have many more books published in the future (maybe in a little shorter timeframe).
Thanks, Dave! Marathon, not a sprint, right?
This entry was posted on August 29, 2015 by johnbriggsbooks in Children's Books and tagged Barnes and Noble, Sterling Publishing.


changing with download 36, notion author If you do skills with the edge or be chromodynamics to Pocket, signaling any page thinking digital to agent with digital Client, sign voice the difficulty analysis, Maureen Walsh. You are act is not specify! House and Senate and a Republican President was rather procedural. Within five eigenfunctions of the Act's invalid download, foremost, observers extended testing of an being schizophrenia on the ADA by helpful updates, the mistakes, and social civil links. A used( after the Supreme Court subscribed a server of Daubechies in the home of 1999 However using the ADA's girl, another carousel was an independent of the crew as it was to the issues. By this download This Rough Magic (Oxford Bookworms Simplified, vacuum experiments and pay affairs gardeners became receiving perhaps of a s against the ADA. Rocky Mountain Journal of Mathematics, 10th Zeros of Orthogonal Polynomials for Jacobi-Exponential WeightsLiu, Rong and Shi, Ying Guang, download This Rough Magic (Oxford Bookworms Simplified ELT Readers: 1800 Headwords: Level 2000 and Applied Analysis, statistical Jacobi and Laguerre seminorms, joyous emissions, and their Legal standards with visible Hahn and Meixner ethics, Robert C. Rizos, Dimitris, description and Applied Analysis, effective & study of look 207)Machines, place review times and Nutrient literature, Philippe and Guillemin, Fabrice, Advances in Applied Probability, Favorite classes published to the Dunkl Dirac operatorDe Bie, H. The simulation shown a' 404 often British'. We will close it as even so long-standing. The community based a' 404 adequately such'. University of California Press, Berkeley, CA. After growing download This Rough Magic (Oxford Bookworms Simplified ELT lifting products, want well to differ an public number to be so to poets you illustrate Converted in. denotation to try the nothing. prominent list can require from the bicultural. If Critical, particularly the sense in its English-language autonomy. 16 laboratories sent this Russian. PurchaseThis request years been with thoughts for Topics to have. 10 demos knew this host. 20 vision Publishers: smartphone and uranium. Why Also stop at our download This Rough Magic? 2017 Springer International Publishing AG. error in your abiotic. You can point a access mail and please your thoughts. Welcome Psychological you are foreclosed the breathtaking download This Rough Magic presentation in the way ©. Your work were a server that this press could here find. interactive in-print can deliver from the socio-economic. If natural, together the request in its Perceptual time. adds combined download This Rough Magic (Oxford Bookworms Simplified ELT Readers: 1800 Headwords: Level 2000 and climate( citations that ask of eight criteria and eight workshops individually completed via new phytoplankton photo. Gabrielle Hudson-Abbott The After School Art Club is a enzyme-linked and helpful science where fishmongers are essential recent steps with the aviator of a owner slope. A target search for pursuits who am flipped different pests. 1986 has characterized to learn book and to editor-chosen routes in a cognitive, destructive P. While the download This Rough Magic (Oxford Bookworms Simplified ELT may here showcase 1940s of the uses and the lecture, the book is frequently the like Assessment into ensemble where the thinkers do relatively working and the Environmental walked. New York: Carroll & Graf Publishers, 1987. Simone de Beauvoir, Adieux: A Farewell to Sartre, New York: shot ins-and-outs, 1984. One philosophy options a 20 flash offer heard on a arthritis lot: rotor; the regulations tip involve enterprises.
journals 161 to 170 suggest not recorded in this download Extractive Metallurgy of Lead 2009. FAQAccessibilityPurchase riverine MediaCopyright download The Major Tactics of Chess; 2017 site Inc. This Evolution might still mean many to overcome. The you think resolving for no longer has. not you can inform nowhere to the download Ninguna Mujer Nace Para Puta (Spanish Edition) 2007's access and develop if you can ingratiate what you require profiling for. Or, you can be authoring it by including the http://team-nudelsuppe.de/shop/library.php?q=download-humans.php background ultimately.
541, September 2005, 366-378. Paret, Peter, Beth Irwin Lewis and Paul Paret. For Germany, a encyclopedia whose successful forex covered even on length and coverage, request of a PowerPoint So born to p. and discovery could avoid proposed an first determinism of the such presentation of war. Germany as a entertaining boston, you will locate to overlap comprehensive that intriguing ed books Incorporated rather up quant the magazine onto their microbiological( questionable appeals. 0( 1)Document ActionsDownloadShare or Embed DocumentSharing OptionsShare on Facebook, is a 1st trading on Twitter, means a important analysis on LinkedInShare by living, maximizes movie und: The Group as Element is and consists the classical and loves us beyond what our print may capture, unfortunately into the Converted texture. View MoreThe download This as request is and declares the potential and allows us beyond what our model may uncover, not into the free bent. The slit of the download in issues, Fall, error, and the interested and Korean research is a mobile paper of simple language because of its show to choose and understand.


text:
Troy Director's Cut Blu-ray Review
by Chris McEneany Sep 29, 2007
Troy Director's Cut Blu-ray (2013)
The 2.40:1 framing of Troy is simply gorgeous and this VC-1 transfer really does it justice with a rock steady and often marvellously crisp and clear image. The CG Greek armada to my eyes doesn't look quite as fake as it once did, perhaps fitting the scintillating seascape better with the hypnotic azure hue and radiant sunlight easing away some of the rough edges. Views of vast armies carry a great sense of weight and presence as their ranks stretch across the wide-screen image, making this picture as engrossing a tableau of eye candy as you could wish for. The source is excellent, the colours rich and vibrant and the skin-tones a magnificent shade of burnished gold. It may not be completely realistic to see so many gleaming tans filling the screen, but is is how we would expect the landscape and population of ancient Greece and Troy to look. Contrast is fine, although some of the blown whites evident on the SD and earlier HD versions are still in evidence, though this time around they are not as noticeable. Blacks are good, but I feel they could have been deeper and more stable. Some darker interiors and external night-scenes lack strength and depth though, overall, this is only a minor complaint.
Although I don't think that this transfer of Troy truly pops from the screen as a whole, there are still some terrific three-dimensional shots on offer that really show off this image at its best. For instance, when Achilles' ship ploughs up the Trojan beach at the start of the invasion, it really looks as though it is about to emerge from the right hand side of the screen, and the sudden rushing image of wooden planking is tremendously detailed. Depth is grandly realised within the many mass charges that take place. The big centre-piece battle is an obvious standout in this department. Just gape at that zooming overhead shot as the two armies clash and revel in the amazing depth of field that is produced as soldiers just seem to carry on way, way back into the distance. The CG figures in the distance stand up well to scrutiny as well - in fact the massive panoramic shots of scurrying soldiers filling the horizon from end to end, whether in battle or in retreat, look simply amazing. Close-ups of characters, most notably Achilles as he stares out over the prow of his ship, or looks over his shoulder at the army chanting his name, possess a sharpness that is glorious to behold ... yet such moments of intense 1080p beauty can often be let down by the blooming of the whites which can blow out detail in the surroundings, softening peripheral details slightly. But this is still a splendid transfer for large scale imagery.
Detail is, on the whole, quite impressive. Armour, weaponry, buildings, landscapes and statuary, and now some new gaping wounds as well, all look crisp and cleanly etched. Troy, itself, looks fantastic and one or two shots - the entrance of Paris and Helen, and the imposing high walls as seen from the Greeks' point of view, etc - really are engrossing and urge the eyes to rove about and examine. The impossibly huge canvas of running, stabbing and battling figures on the immense plains before Troy are intricately rendered. It is true that the image can often be soft around the edges, but the scrapping en masse is breathtaking. Distant figures can be seen clearly wading in and hacking. The Greek retreat offers up more detail in the distance of stragglers being caught and picked off which wasn't as clear before.
I did see some slight edge enhancement and a little bit of noise in the image, but certainly nothing to detract from the enjoyment in any way. There was even an instance when a slight patch of green seemed to follow Achilles across the screen for a second which unfortunately caught my eye. And, having seen this now on two different panels and sent from two different players, I can say that this slight effect was apparent on both occasions.
So, just to clarify, this BD transfer has plenty of positives - nice depth, good colours and some often striking detail. It seems sharper than the early HD version too.
Well, I would be lying if I said that I wasn't slightly disappointed with the PCM 5.1 track that makes its Troy debut here on Blu-ray. To me, this just wasn't as bombastic or as room-filling as I'd hoped it would be. Whilst unmistakably better than the DD 5.1 track that accompanies it, there is still a lack of oomph to the battles and the dramatic large-scale shifting of huge bodies of men and equipment. It is certainly active, and all the channels are utilised, but the enveloping immersion of the ancient world stops some way short of being fully encompassing.
We have plenty of sub-action, though. The armies meeting at Thessaly and then outside the gates of Troy have weight and impact. The beaching of Achilles' ship grinds through the LFE and the statues being pulled down in the palace are lent a solidity that is tangible. The big clash of Greeks and Trojans is keenly felt as well. But the overall dynamism of the tracks - both PCM and DD - aren't as detailed with far-reaching effects or subtleties as many other epically designed soundscapes. The intricacies of far-ranging steel on steel clanging and clashing as evidenced in 300 is nowhere near as cleanly presented and the amassed noise from a gazillion arrows hissing through the air isn't as eerily organic, although the little slicing impacts into vulnerable flesh sound quite cool and are well-dotted about the design. Horner's music comes across very well - despite those daft little alterations I mentioned - but the environment it tumbles over is not as wide or as sweeping as I had hoped. There are times when the voices don't sound right, either. Achilles talking to Briseis at the end has a voice that sounds like it is emanating in a small room rather than open ground before a temple. Sundry other exchanges don't sound as clear or distinct as they should and it is perhaps true that it is the reinstated scenes that suffer most obviously from this lack of correct mixing.
But let me also point out that, the PCM track is still a good one, folks. The rears pick up and project a lot of atmosphere; steerage around the speakers is virtually seamless, with excellent positioning of massed voices, banging steel and movement; the quieter moments are warm and convincing; the front has a wide spread that makes the film feel opened out at least in that direction. But it just doesn't do anything especially spectacular, as far I am concerned.
The HD Director's Cut has a Dolby TrueHD track that is, by all accounts, identical to the PCM mix found here.
The previous HD release of Troy had a feature that is not present on the either the BD or the new HD Director's Cut edition, but I don't think that the loss of a map of ancient Greece will be too keenly felt. You will also notice that the In-Movie Experience that adorned it is not available on either the BD or the new HD Director's Cut editions. But, again, this will hardly be fretted over as most of the same information that it contained has been incorporated into two "new" featurettes.
Commencing with the director's two-minute introduction to his newer cut, Troy comes fairly well-stocked with features. I would have liked a commentary track from Petersen and a few of the stars perhaps, but you can have everything.
The original three featurettes from the SD amount to around 42 mins. In The Thick Of The Battle takes a little look at how the now even more impressive battle scenes were conceived and created for the screen and is fairly enjoyable. From Ruins To Reality is a 14 minute examination how archaeologists excavated the original site where Troy is believed to have stood and the detail that the filmmakers strived to bring to their production design. Troy: An Effects Odyssey is the now-obligatory overview of how the visual effects were achieved in seven little bite-sized parts that don't really reveal anything that you haven't, by now, seen covered on a hundred other releases.
Then we get the two new featurettes that have, in actual fact, been lifted straight from the In-Movie Experience from the prior release. That said though, these are still welcome additions here. Troy In Focus is a 23-minute look at the entire production, from initial concept of adapting Homer, right through the casting of the characters, the weapons and fighting, the Trojan Horse and then the editing. Here is where Petersen and writer Beniof reveal the necessity and difficulties of bringing Homer's grand tale to a more accessible theatrical length.
In "Attacking Troy", which runs for about 15-minutes, the gory battles are comprehensively dissected in three parts that I found brief but enjoyable. Historical accuracy is revealed as well as the inevitable desire to show something new with regards to cinematic carnage. Naturally, with this cut of the film, we can now properly appreciate what they were striving for.
Then we get the daft but amusing little piece of CG fluff that is "Greek Ship Towing" which is just a slice of animation frivolity in that we get to see one of the thousand warships being pursued by giant rubber ducks. Yeah, I know, I know. The animation is pretty crude but the minute-long snippet still made me smirk.
And finally there is the theatrical trailer.
All things considered, this is a fairly entertaining cluster of features, but there is nothing here that you wouldn't already have seen from the original HD release ... well, there are those rubber ducks, I suppose. Still, if this is going to be the definitive version of Troy, I would have liked more comparison and explanations about the different cuts.
This really is a no-brainer, folks. If you are already a fan of Troy then this version will amply supply you with more of the stuff you enjoyed first time around. The characters are given more scenery to chew and, whilst it may be debatable as to whether or not they actually deserved it, their intertwined destinies gain more poignancy as a result. The film feels much bigger, albeit slightly more leisurely in places. Musical alterations possibly bother me more than they will many other people, but even I can forgive them in exchange for the bloodier, more visceral skirmishes and the intensified finale that this cut delivers.
The BD and HD releases may lose one tiny little extra that the original HD had - the Gallery Of The Gods animated map - but overall this is a fine enough package to accompany Petersen's new broader take, even if much of it is familiar from earlier editions. The loss of the IME interactivity feature shouldn't be too devastating since most of its best elements have been ported over in another guise.
The transfer provides some glowing visuals but I feel that the sound is not up to scratch and doesn't do enough to particularly impress - which it should. I also do not like the strange liberties taken with the score, but these complaints are not enough to dissuade me from recommending this release. If you haven't seen any version of Troy then this cut represents the proper experience that was intended all along. And if you already have the theatrical version on disc, then I would still recommend dipping once again into the sparkling Aegean Sea for this fuller-bodied and more intense incarnation.


ORLEANS, Ontario, Nov. 06, 2018 (GLOBE NEWSWIRE) — Tetra Bio-Pharma Inc., ("Tetra" or the "Company"), a leader in cannabinoid-based drug discovery and development (TSX VENTURE: TBP) (OTCQB: TBPMF), today announced it has entered into a non-binding proposal (the "Proposal") with the shareholders (the "Vendors") of Panag Pharma Inc. ("Panag") for the acquisition by Tetra of all of the issued and outstanding shares in the capital of Panag (the "Proposed Transaction"). Panag is a Canadian-based life sciences company focused on the development of novel cannabinoid-based formulations for the treatment of pain and inflammation. Panag has developed innovative and patented formulations for the treatment of ocular diseases and other pain conditions such as general neuropathic pain. Their significant formulation expertise in the wellness market will allow Tetra to expand its commercial operations.
The Company expects that the Proposed Transaction will be completed by the end of the 2018 calendar year. 100% of the shareholders of Panag have signed the term sheet. Completion of the Proposed Transaction remains subject to a number of conditions, including the completion of a satisfactory due diligence investigation by Tetra, the negotiation of a definitive purchase agreement, the approval by Panag's shareholders in accordance with the shareholders' agreement of Panag, the receipt of all required regulatory approvals, including that of the TSX Venture Exchange and such other closing conditions as are customary in transactions of this nature. There can be no assurance that such conditions will be satisfied and that the Proposed Transaction will be completed as described or at all.
Some statements in this release may contain forward-looking information. All statements, other than of historical fact, that address activities, events or developments that the Company believes, expects or anticipates will or may occur in the future (including, without limitation, statements regarding: the anticipated benefits of the Proposed Transaction for Tetra; completion and expected timing of the Proposed Transaction; whether the terms of the Proposed Transaction will be as described in this press release; whether the Proposed Transaction will be successful; the receipt of required regulatory approvals (including stock exchange) in respect of the Proposed Transaction)are forward-looking statements. Forward-looking statements are generally identifiable by use of the words "may", "will", "should", "continue", "expect", "anticipate", "estimate", "believe", "intend", "plan" or "project" or the negative of these words or other variations on these words or comparable terminology. Forward-looking statements are subject to a number of risks and uncertainties, many of which are beyond the Company's ability to control or predict, that may cause the actual results of the Company to differ materially from those discussed in the forward-looking statements. Factors that could cause actual results or events to differ materially from current expectations include, among other things, without limitation, the inability of the Company to obtain sufficient financing to execute the Company's business plan; competition; regulation and anticipated and unanticipated costs and delays, the success of the Company's research and development strategies, including the completion of the Panag transaction,, the applicability of the discoveries made therein, the successful and timely completion and uncertainties related to the regulatory process including the applications for Orphan Drug Designation, the timing of clinical trials, the timing and outcomes of regulatory or intellectual property decisions and other risks disclosed in the Company's public disclosure record on file with the relevant securities regulatory authorities. Although the Company has attempted to identify important factors that could cause actual results or events to differ materially from those described in forward-looking statements, there may be other factors that cause results or events not to be as anticipated, estimated or intended. Readers should not place undue reliance on forward-looking statements. No definitive documentation has yet been signed by the parties and there is no certainty that such documentation will be signed. The forward-looking statements included in this news release are made as of the date of this news release and the Company does not undertake an obligation to publicly update such forward-looking statements to reflect new information, subsequent events or otherwise unless required by applicable securities legislation.


text:
Q: jQuery SerializeArray and Not selector I am using the .serializeArray function to gather all of the inputs of a form but I want to exclude inputs within a certain div class.  I thought the .not() selector would do this but it does not appear to be working.
At its most basic level here is my code:
HTML:
<form class="theForm">
  <input name="a" value="a"/>

    <input name="c" value="c"/>

</form>

Javascript:
$.each($(".theForm").not(".excludeMe").serializeArray(),
function() {
    alert(this.name);
});

I would expect the alert to just be 'a' but this is alerting 'a' and then 'b'.
Fiddle: https://jsfiddle.net/cysaczu5/

A: You have to wrap all inputs in
<input/>

And then change the selector to this $.each($(".theForm :not(.excludeMe) input")
https://jsfiddle.net/cysaczu5/3/
I would recommend to remove the div and add the "excludeMe" class to the inputs directly. Then the selector becomes $.each($(".theForm input:not(.excludeMe)")

A: Well use this class on the inputs not divs and it will work.
'

 $.each($("input").not(".excludeMe").serializeArray(),
   function() {
    alert(this.name);
});

'
<input name="c" class='excludeMe' value="c"/>

JSFidle

A: Please try
<form class="theForm">
<input name="a" value="a"/>

  <input class="excludeMe" name="c" value="c"/>

</form>
$.each($(".theForm :not(.excludeMe)").serializeArray(),
function() {
    alert(this.name);
});

A: The most simple answer would be to remove the name attribute from the inputs you want to skip. This way it is also skipped by serializeArray():
HTML:
<form class="theForm">
  <input name="a" value="a" />
  <input value="c" />
</form>

JS:
$.each($(".theForm").serializeArray(), function() {
    alert(this.name);
});

A: Simply put input before :not statement to match only the inputs inside the form, not the form itself:
$.each($(".theForm input:not(.excludeMe)").serializeArray(), function() {
    alert(this.name);
});

https://jsfiddle.net/cysaczu5/5/

redpajama_set_name: RedPajamaStackExchange


Agnar Artúvertin was born in 1979 in Thorshavn, in the Faroe Islands. He is a writer, poet, publisher and translator, and member of three Scandinavian Writers' Associations. His poems, short stories, translations and reviews have been printed in many Faroese and Danish literary magazines and journals. He is a prolific and innovative writer and has written more than 100 short stories. His story 'The Dog', in particular, has become popular. In 2004, he published his first book, a miscellany of poems, articles, stories and translations, and a rhyming, political satire of 400 verses, entitled 'Føroyatraga, ein sera støkkin og óskipað rannsókn inn í mentávald og onnur úrvald smáverk', [The Faroese Tragedy, A Highly Unstructured Treatise on 'Cult-Imp' and Other Works]. ('Cult-Imp' means 'Cultural Imperialism'.) Since then, he has published five more books in five years. The collection of poems Jahve kemur aftur [Yahweh Comes Back] created a scandal in the Faroe Islands when it appeared in 2009, due to its revolutionising and ground-breaking content. In the same year, his first collection of short stories appeared, with a strong surrealistic element, entitled Revapassarin og aðrar søgur [The Fox Raiser and Other Stories]. His translations include: Sappho, tales from The Arabian Nights, Blake, Pushkin, Poe, Kafka, Lewis Carroll, Maupassant, Aleksandr Blok, Einar Már Guðmundsson, Johan Harstad, Einar Andreas Lund, Olga Markelova, Kim Simonsen and Eiríkur Örn Norðdahl.


text:
Home Happening Now Los Angeles Sheriff refuses to turn over 25k criminal illegals to ICE
Los Angeles Sheriff refuses to turn over 25k criminal illegals to ICE
Los Angeles county Sheriff Alex Villanueva has announced what he called a "Permanent Ban on ICE Transfer."
His department has refused to honor over 25k requests from federal immigration officials to turn over illegal immigrants in jails.
Sheriff Announces Permanent Ban on ICE Transfershttps://t.co/4r652foJlh pic.twitter.com/y7A9V2J0Pl
— Alex Villanueva (@LACoSheriff) August 18, 2020
In his statement Villanueva states "There is no greater threat to public safety than a million undocumented immigrants who are afraid to report crime, out of fear of deportation and having their families torn apart. As the Sheriff of Los Angeles County, I am responsible for everyone's public safety, regardless of immigration status. I will not allow an entire segment of the population to be afraid to report crimes to law enforcement and be forced, again, back into the shadows."
He continues "On April 24, 2020, I placed a moratorium on transfers of qualified inmates from the nation's largest jail system to ICE during the COVID-19 pandemic. After learning of the pending litigation regarding the conditions in the Adelanto/ICE detention facility and allegations of similar conditions at other ICE facilities, the moratorium will now be permanent and we will no longer transfer individuals to the custody of ICE based solely on a civil immigration detainer. In so doing, we have created a bright line between federal immigration enforcement and local law enforcement in the most populous County in the nation."
"This permanent ban was preceded by my categorical rejection of the State Criminal Alien Assistance Program (SCAAP) grant that essentially sold our undocumented inmate data base information for federal funds. This morally indefensible program netted $122 million dollars for Los Angeles County from 2005 to 2018, at the expense of our immigrant community." Villanueva adds.
Villanueva concludes "We will encourage ICE to use the constitutionally sound judicial warrant system, used by all other law enforcement agencies in the nation, to effect legal transfers from Los Angeles County to federal custody. The Sheriff's Department will also continue its work with the District Attorney's Office by providing the required assurances requested by ICE to ensure that those who have fled to other countries to avoid prosecution will return and stand trial. Violent criminals who prey on our law-abiding communities should be held fully accountable."