text:
#ifndef TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_
#define TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_

#include <memory>
#include <vector>

#include "tensorflow/core/framework/dataset.h"
#include "tensorflow/core/framework/function.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/gtl/array_slice.h"
#include "tensorflow/core/lib/random/random.h"
#include "tensorflow/core/platform/macros.h"

namespace tensorflow {

class Device;
class OpKernelContext;
class ResourceMgr;

namespace data {

class CapturedFunction;
class InstantiatedCapturedFunction;

Status MakeIteratorFromInputElement(
    IteratorContext* ctx, const std::vector<Tensor>& input_element,
    int64 thread_index, const InstantiatedCapturedFunction& inst_captured_func,
    StringPiece prefix, std::unique_ptr<IteratorBase>* out_iterator);

// `InstantiatedCapturedFunction` encapsulates all the runtime support needed
// to execute a tensorflow function.
//
// While `CapturedFunction` encapsulates constant attributes of the function,
// such as its name and captured arguments, `InstantiatedCapturedFunction`
// encapsulates runtime aspects, such as `FunctionLibraryRuntime` and function
// handle.
//
// The `Iterator` related classes use `InstantiatedCapturedFunction` to execute
// functions outside of the normal `OpKernel::Compute()` context.
class InstantiatedCapturedFunction {
 public:
  ~InstantiatedCapturedFunction();

  // Runs the instantiated captured function. This method takes ownership of
  // the tensors in `args`, in order to be able to deallocate them as early as
  // possible. Use `RunWithBorrowedArgs()` if the caller needs to retain
  // ownership of the `args`.
  Status Run(IteratorContext* ctx, std::vector<Tensor>&& args,
             std::vector<Tensor>* rets) const;

  // Synchronously runs the captured function on the given `args`, and stores
  // the results in `*rets`. Prefer to use `Run()` or `RunAsync()` when
  // possible.
  Status RunWithBorrowedArgs(IteratorContext* ctx,
                             const std::vector<Tensor>& args,
                             std::vector<Tensor>* rets) const;

  // Synchronously runs the captured function on the given `args`, and stores
  // the results in `*rets`. Prefer to use `Run()` or `RunAsync()` when
  // possible. This can be useful for calling a captured
  // function in cases where an `IteratorContext*` is not available
  // (such as a destructor).
  Status RunInstantiated(const std::vector<Tensor>& args,
                         std::vector<Tensor>* rets);

  // Asynchronously runs the captured function on the given `args`, stores
  // the results in `*rets`, and calls the given `done` callback when the
  // function returns. This method takes ownership of the tensors in `args`,
  // in order to be able to deallocate them as early as possible.
  void RunAsync(IteratorContext* ctx, std::vector<Tensor>&& args,
                std::vector<Tensor>* rets,
                FunctionLibraryRuntime::DoneCallback done,
                const string& prefix) const;

 private:
  InstantiatedCapturedFunction(
      FunctionLibraryRuntime* lib, FunctionLibraryRuntime::Handle f_handle,
      DataTypeVector ret_types,
      std::function<void(std::function<void()>)> runner,
      CapturedFunction* captured_func);

  friend class CapturedFunction;

  FunctionLibraryRuntime* const lib_;
  const FunctionLibraryRuntime::Handle f_handle_;
  const DataTypeVector ret_types_;
  std::function<void(std::function<void()>)> captured_runner_;
  CapturedFunction* const captured_func_;

  TF_DISALLOW_COPY_AND_ASSIGN(InstantiatedCapturedFunction);
};

struct ShortCircuitInfo {
  std::vector<int> indices;
  std::vector<bool> can_move;
};

// Metadata shared across all captures of the same function.
class FunctionMetadata {
 public:
  struct Params {
    bool is_multi_device_function = false;
    bool use_inter_op_parallelism = true;
  };

  // Creates a new instance of the `FunctionMetadata` class, fetching function
  // from a context argument.
  static Status Create(tensorflow::OpKernelConstruction* ctx,
                       const string& func_name, Params params,
                       std::shared_ptr<FunctionMetadata>* out_metadata);

  // Creates a new instance of the `FunctionMetadata` class, using the provided
  // function.
  static Status Create(tensorflow::OpKernelConstruction* ctx,
                       NameAttrList&& func, Params params,
                       std::shared_ptr<FunctionMetadata>* out_metadata);

  // Returns the named list of function arguments.
  const NameAttrList& func() const { return func_; }

  // Indicates whether the function is a multi-device function.
  bool is_multi_device_function() const { return is_multi_device_function_; }

  // Returns a borrowed pointer to the function library that contains the
  // transitive closure of definitions used by the function.
  const FunctionLibraryDefinition* lib_def() const { return lib_def_.get(); }

  // Returns short-circuit information.
  const ShortCircuitInfo& short_circuit_info() const {
    return short_circuit_info_;
  }

  // Indicates whether to use inter-op parallelism for execution of the
  // function.
  bool use_inter_op_parallelism() const { return use_inter_op_parallelism_; }

 private:
  FunctionMetadata(NameAttrList&& func, Params params)
      : func_(std::move(func)),
        is_multi_device_function_(params.is_multi_device_function),
        use_inter_op_parallelism_(params.use_inter_op_parallelism) {}

  NameAttrList func_;
  bool is_multi_device_function_ = false;
  std::unique_ptr<FunctionLibraryDefinition> lib_def_ = nullptr;
  ShortCircuitInfo short_circuit_info_;
  bool use_inter_op_parallelism_ = true;
};

// A `CapturedFunction` encapsulates a TensorFlow function, plus any "captured"
// arguments that it closed over in the user program.
class CapturedFunction {
 public:
  // Creates a new instance using a list of named attributes, fetching captured
  // inputs from a context argument.
  static Status Create(OpKernelContext* ctx,
                       const std::shared_ptr<const FunctionMetadata> metadata,
                       const string& argument_name,
                       std::unique_ptr<CapturedFunction>* out_function);

  // Creates a new instance using a list of named attributes, using provided
  // captured inputs.
  static Status Create(OpKernelContext* ctx,
                       const std::shared_ptr<const FunctionMetadata> metadata,
                       std::vector<Tensor>&& captured_inputs,
                       std::unique_ptr<CapturedFunction>* out_function);

  // Adds the definition of this captured function into the given graph,
  // returning its captured inputs and types through the respective output
  // arguments.
  Status AddToGraph(SerializationContext* ctx,
                    DatasetBase::DatasetGraphDefBuilder* b,
                    std::vector<Node*>* other_arguments,
                    DataTypeVector* other_arguments_types) const;

  // Instantiates this function for use in the given context, providing an
  // InstantiatedCapturedFunction that can be used to execute functions.
  Status Instantiate(IteratorContext* ctx,
                     std::unique_ptr<InstantiatedCapturedFunction>*
                         instantiated_captured_function);

  // Returns the additional captured inputs that will be passed to the function.
  const std::vector<Tensor>& captured_inputs() const {
    return captured_inputs_;
  }

  // Returns the named list of function arguments.
  const NameAttrList& func() const { return metadata_->func(); }

  // Indicates whether the function is multi-device.
  bool is_multi_device_function() const {
    return metadata_->is_multi_device_function();
  }

  // Returns the transitive set of function definition required to instantiate
  // this function.
  const FunctionLibraryDefinition* lib_def() const {
    return metadata_->lib_def();
  }

  // If every function output corresponds to one of its inputs, the method
  // returns the mapping from output indices to input indices. Otherwise, it
  // returns an empty list.
  const ShortCircuitInfo& short_circuit_info() const {
    return metadata_->short_circuit_info();
  }

  // Indicates whether the function should use inter op parallelism.
  bool use_inter_op_parallelism() const {
    return metadata_->use_inter_op_parallelism();
  }

 private:
  CapturedFunction(const std::shared_ptr<const FunctionMetadata> metadata,
                   std::vector<Tensor> captured_inputs);

  const std::shared_ptr<const FunctionMetadata> metadata_;
  const std::vector<Tensor> captured_inputs_;

  TF_DISALLOW_COPY_AND_ASSIGN(CapturedFunction);
};
}  // namespace data

// TODO(b/114112161): Remove these aliases when all users have moved over to the
// `tensorflow::data` namespace.
using data::CapturedFunction;

}  // namespace tensorflow

#endif  // TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_


text:
This repository contains another simple but powerful boilerplate for creating frontend themes.
It sets up a powerful an assistive environment for development and to write in meta language to common web technologies.

## Introduction
It's a simple but powerful boilerplate for building frontend themes. However it is not perfect
at the time - and won't ever be - so I will update it continuously. You are welcome to open
an issue or creating a pull request.

## Requirements
You need to have:
* [`Node.js`](https://nodejs.org/) (and `npm`) installed to your system (I tested it with `v6.2.1`)
* [`Bower`](https://bower.io/) installed for vendor package management

Also recommended is:
* [`gulp-cli`](https://www.npmjs.com/package/gulp-cli) (`npm install -g gulp-cli`)

***NOTE:*** Gulp and Bower are also installed as `devDependencies`. You should yet only using
the local version of gulp because it's a alpha version installed via "git clone".

All scripts and tasks are fitted to OSX/Linux so you may experience weird behaviour on Windows or others.

## Getting started
The bootstrap task for your next theme is very easy:
* Pull the latest `master` from this repository and copy all files into your new project's folder **or**
* Fork this repository

Next step is to install all (development) dependencies: `npm install && bower install`.

You may also follow this short todo list to change the package meta information:
1. Update `package.js` and `bower.json` with your details
2. Maybe change the license
3. Remove or edit the default `index.html` file
4. Extend or remove the `humans.txt`
5. Update the coding standard in `.editorconfig`, `.eslintrc` and `.stylelintrc` to your needs
6. Remove the `CHANGELOG`
7. Remove/Clear this readme file

### Extending
When you want to use additional frameworks you may add them with npm or bower.
While any package installed with bower is meant to be used in frontend npm packages are
meant for developing in first line.

For example if you want to include a jQuery plugin install it with bower
```
bower install --save <package>
```
and include it in your html's heads
```
<script src="dist/vendor/<package>/somelib.js"></script>
```

When you want to use a frontend framework (e.g. [Bootstrap](getbootstrap.com)) it's nice if
it provides sass files. You can require it with bower, to include some scripts if it has, and
pass the sass files to the sass compiler in the gulp task in `gulpfile.js`.
```JavaScript
	...
	.pipe(sass({
		includePaths: ['path/to/sass/files']
	})
	...
```

### Workflow
When you are developing your project, run the following commands:
```
npm start
```
or use the `gulp-cli` to run custom or separated tasks
```
gulp lint
```

The `default` and `watch` gulp task will watch the files and compile them if a change was detected.
`npm start` will just run the gulp default's task.

#### Folder structure
The structure you introduce in the `source directory` (`src/`) will be preserved in the `distribution directory` (`dist/`).
So you can use a splitted directory tree, where each asset type is in its own directory (e.g. scripts in `scripts`, styles in `styles`, etc.):
```
src/
|-- scripts
|   `-- app.js
|-- styles
|   `-- app.scss
`-- templates
    `-- main.pug
```
Or you can use a module inspired directory tree where each asset type is in the folder of its belonging module:
```
src/
|-- app
|   |-- app.js
|   |-- app.scss
|   `-- template.pug
`-- module1
    |-- helper.js
    `-- main.js
```
Of course you can mix them or use your own.
Through the ["globstar"](https://github.com/isaacs/node-glob#glob-primer) you are free to use every structure.

The `assets` folder may ship assets, like images.

#### Linting
You can lookup all SCSS linting rules here: [https://stylelint.io/user-guide/rules/](https://stylelint.io/user-guide/rules/).
There are more detailed information about what is wrong.

#### CI
There's already a configuration for the GitLab CI. On every push it triggers a linting.
On pushes to master it will build an artifact. The general workflow would be developing in a `develop` branch,
while merging into a `master` branch means a release.

If you want to use another CI or compile it locally you can use the gulp `build` tasks defined in `gulpfile.js`.

## Special Thanks
This boilerplate was made possible by all these cool and powerful tools that are running in
the background and help us every day.

**Open Source ist awesome!**

Tools used:
* [Node.js](https://nodejs.org/)
* [Bower](https://bower.io/)
* [Gulp](http://gulpjs.com/)
* [Babel](https://babeljs.io/)
* [ESLint](http://eslint.org/)
* [SASS](http://sass-lang.com/)
* [Pug](https://pugjs.org/)
* [stylelint](https://stylelint.io/)
* [UglifyJs2](https://github.com/mishoo/UglifyJS2)
* [clean-css](https://github.com/jakubpawlowicz/clean-css)
* ... and many more!
* ... and all their subpackages

**Thank you!**

## License
This software is under [MIT License](LICENSE). You are free to copy, modify, distribute this boilerplate.
You can build your own boilerplate upon it or bootstrap a theme out of it.

However this software uses several tools and programs which have different licenses.

redpajama_set_name: RedPajamaGithub


text:
package org.opendatakit.database.service;

import android.content.ContentValues;
import org.opendatakit.aggregate.odktables.rest.entity.RowFilterScope;
import org.opendatakit.database.data.BaseTable;
import org.opendatakit.database.data.ColumnList;
import org.opendatakit.database.data.KeyValueStoreEntry;
import org.opendatakit.database.data.OrderedColumns;
import org.opendatakit.database.data.TableDefinitionEntry;
import org.opendatakit.database.data.TableMetaDataEntries;
import org.opendatakit.database.data.UserTable;
import org.opendatakit.database.queries.ArbitraryQuery;
import org.opendatakit.database.queries.BindArgs;
import org.opendatakit.database.queries.ResumableQuery;
import org.opendatakit.database.queries.SimpleQuery;
import org.opendatakit.exception.ActionNotAuthorizedException;
import org.opendatakit.exception.ServicesAvailabilityException;
import org.opendatakit.provider.DataTableColumns;

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

/**
 * Used in CommonApplication
 */
@SuppressWarnings("unused")
public class UserDbInterfaceImpl implements UserDbInterface {

  private final InternalUserDbInterface internalUserDbInterface;

  /**
   * Access this ONLY through getMetadata(tableId) and putMetadata(tableId, entries).
   * Multiple threads may be accessing this.
   */
  private final Map<String, TableMetaDataEntries> privateMetaDataCache = new HashMap<>();

  /**
   * Access this ONLY through internalGetAdminColumns()
   * Multiple threads may be accessing this.
   */
  private String[] internalAdminColumns = null;

  public UserDbInterfaceImpl(InternalUserDbInterface internalUserDbInterface)
      throws IllegalArgumentException {
    if (internalUserDbInterface == null) {
      throw new IllegalArgumentException("Database Interface must not be null");
    }

    this.internalUserDbInterface = internalUserDbInterface;
  }

  private static TableMetaDataEntries filterEntries(TableMetaDataEntries allEntries,
      String partition, String aspect, String key) {
    if (partition == null && aspect == null && key == null) {
      return new TableMetaDataEntries(allEntries);
    }

    TableMetaDataEntries entries = new TableMetaDataEntries(allEntries.getTableId(),
        allEntries.getRevId());

    for (KeyValueStoreEntry entry : allEntries.getEntries()) {
      if ((partition == null || entry.partition.equals(partition)) && (aspect == null
          || entry.aspect.equals(aspect)) && (key == null || entry.key.equals(key))) {
        entries.addEntry(entry);
      }
    }
    return entries;
  }

  private TableMetaDataEntries getMetadata(String tableId) {
    synchronized (privateMetaDataCache) {
      return privateMetaDataCache.get(tableId);
    }
  }

  private void putMetadata(String tableId, TableMetaDataEntries entries) {
    synchronized (privateMetaDataCache) {
      privateMetaDataCache.put(tableId, entries);
    }
  }

  public InternalUserDbInterface getInternalUserDbInterface() {
    return internalUserDbInterface;
  }

  private synchronized String[] internalGetAdminColumns() throws ServicesAvailabilityException {
    if (internalAdminColumns != null) {
      return internalAdminColumns;
    } else {
      internalAdminColumns = getAdminColumns();
      return internalAdminColumns;
    }
  }

  /**
   * Return the active user or "anonymous" if the user
   * has not been authenticated against the server.
   *
   * @param appName the app name
   * @return the user reported from the server or "anonymous" if
   * server authentication has not been completed.
   */
  @Override
  public String getActiveUser(String appName) throws ServicesAvailabilityException {

    return internalUserDbInterface.getActiveUser(appName);
  }

  /**
   * Return the roles and groups of a verified username or google account.
   * If the username or google account have not been verified,
   * or if the server settings specify to use an anonymous user,
   * then return an empty string.
   *
   * @param appName the app name
   * @return null or JSON serialization of an array of ROLES. See RoleConsts for possible values.
   */
  @Override
  public String getRolesList(String appName) throws ServicesAvailabilityException {

    return internalUserDbInterface.getRolesList(appName);
  }

  /**
   * Return the default group of the current user.
   *
   * @param appName the app name
   * @return null or the name of the default group for this user.
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public String getDefaultGroup(String appName) throws ServicesAvailabilityException {

    return internalUserDbInterface.getDefaultGroup(appName);
  }

  /**
   * Return the users configured on the server if the current
   * user is verified to have Tables Super-user, Administer Tables or
   * Site Administrator roles. Otherwise, returns information about
   * the current user. If the user is syncing anonymously with the
   * server, this returns an empty string.
   *
   * @param appName the app name
   * @return null or JSON serialization of an array of objects
   * structured as { "user_id": "...", "full_name": "...", "roles": ["...",...] }
   */
  @Override
  public String getUsersList(String appName) throws ServicesAvailabilityException {

    return internalUserDbInterface.getUsersList(appName);
  }

  /**
   * Obtain a databaseHandleName
   *
   * @param appName the app name
   * @return dbHandleName
   */
  @Override
  public DbHandle openDatabase(String appName) throws ServicesAvailabilityException {

    return internalUserDbInterface.openDatabase(appName);
  }

  /**
   * Release the databaseHandle. Will roll back any outstanding transactions
   * and release/close the database handle.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   */
  @Override
  public void closeDatabase(String appName, DbHandle dbHandleName)
      throws ServicesAvailabilityException {

    internalUserDbInterface.closeDatabase(appName, dbHandleName);
  }

  /**
   * Create a local only table and prepend the given id with an "L_"
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param columns      the columns in the table
   * @return a set of the columns in the newly created table
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public OrderedColumns createLocalOnlyTableWithColumns(String appName, DbHandle dbHandleName,
      String tableId, ColumnList columns) throws ServicesAvailabilityException {

    return internalUserDbInterface
        .createLocalOnlyTableWithColumns(appName, dbHandleName, tableId, columns);
  }

  /**
   * Drop the given local only table
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public void deleteLocalOnlyTable(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {

    internalUserDbInterface.deleteLocalOnlyTable(appName, dbHandleName, tableId);
  }

  /**
   * Insert a row into a local only table
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowValues    the values to be added
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public void insertLocalOnlyRow(String appName, DbHandle dbHandleName, String tableId,
      ContentValues rowValues) throws ServicesAvailabilityException {

    internalUserDbInterface.insertLocalOnlyRow(appName, dbHandleName, tableId, rowValues);
  }

  /**
   * Update a row in a local only table
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowValues    the new values for the row
   * @param whereClause  the clause that dictates which row to update
   * @param bindArgs
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public void updateLocalOnlyRows(String appName, DbHandle dbHandleName, String tableId,
      ContentValues rowValues, String whereClause, BindArgs bindArgs)
      throws ServicesAvailabilityException {

    internalUserDbInterface
        .updateLocalOnlyRows(appName, dbHandleName, tableId, rowValues, whereClause, bindArgs);
  }

  /**
   * Delete a row in a local only table
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param whereClause  the clause that dictates which row to delete
   * @param bindArgs     an array of primitive values (String, Boolean, int, double) for
   *                     bind parameters
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public void deleteLocalOnlyRows(String appName, DbHandle dbHandleName, String tableId,
      String whereClause, BindArgs bindArgs) throws ServicesAvailabilityException {

    internalUserDbInterface
        .deleteLocalOnlyRows(appName, dbHandleName, tableId, whereClause, bindArgs);
  }

  /**
   * Get a {@link BaseTable} for this local only table based on the given SQL command. All
   * columns from the table are returned.
   *

   * If any of the clause parts are omitted (null), then the appropriate
   * simplified SQL statement is constructed.
   *
   * @param appName           the app name
   * @param dbHandleName      the database handle to use
   * @param tableId           the table id
   * @param whereClause       the whereClause for the selection, beginning with "WHERE". Must
   *                          include "?" instead of actual values, which are instead passed in
   *                          the selectionArgs.
   * @param bindArgs          an array of primitive values (String, Boolean, int, double) for
   *                          bind parameters
   * @param groupBy           an array of elementKeys
   * @param having            part of the sql query
   * @param orderByColNames   array of columns to order the results by
   * @param orderByDirections either "ASC" or "DESC", corresponding to each column name
   * @param limit             the maximum number of rows to return
   * @param offset            the index to start counting the limit from
   * @return A {@link UserTable} containing the results of the query
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public BaseTable simpleQueryLocalOnlyTables(String appName, DbHandle dbHandleName, String tableId,
      String whereClause, BindArgs bindArgs, String[] groupBy, String having,
      String[] orderByColNames, String[] orderByDirections, Integer limit, Integer offset)
      throws ServicesAvailabilityException {

    if (!tableId.startsWith("L_")) {
      tableId = "L_" + tableId;
    }

    return simpleQuery(appName, dbHandleName, tableId, whereClause, bindArgs, groupBy, having,
        orderByColNames, orderByDirections, limit, offset);
  }

  /**
   * Get a {@link BaseTable} for the result set of an arbitrary sql query
   * and bind parameters on this local only table.
   *

   * The sql query can be arbitrarily complex and can include joins, unions, etc.
   * The data are returned as string values.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param sqlCommand   the query to execute
   * @param bindArgs     an array of primitive values (String, Boolean, int, double) for
   *                     bind parameters
   * @param limit        the maximum number of rows to return (optional)
   * @param offset       the index to start counting the limit from (optional)
   * @return An  {@link BaseTable}. Containing the results of the query
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public BaseTable arbitrarySqlQueryLocalOnlyTables(String appName, DbHandle dbHandleName,
      String tableId, String sqlCommand, BindArgs bindArgs, Integer limit, Integer offset)
      throws ServicesAvailabilityException {

    if (!tableId.startsWith("L_")) {
      tableId = "L_" + tableId;
    }

    return arbitrarySqlQuery(appName, dbHandleName, tableId, sqlCommand, bindArgs, limit, offset);
  }

  /**
   * Get a {@link BaseTable} that holds the results from the continued query. Note that this is
   * just a wrapper of resumeSimpleQuery, which could successfully be used instead.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param query        The original query with the bounds adjusted
   * @return the table with the results for the query
   * @throws ServicesAvailabilityException if the database is down
   */
  @Override
  public BaseTable resumeSimpleQueryLocalOnlyTables(String appName, DbHandle dbHandleName,
      ResumableQuery query) throws ServicesAvailabilityException {

    return resumeSimpleQuery(appName, dbHandleName, query);
  }

  /**
   * SYNC Only. ADMIN Privileges
   *

   * Call this when the schemaETag for the given tableId has changed on the server.
   *

   * This is a combination of:
   *

   * Clean up this table and set the dataETag to null.
   *

   * changeDataRowsToNewRowState(sc.getAppName(), db, tableId);
   *

   * we need to clear out the dataETag so
   * that we will pull all server changes and sync our properties.
   *

   * updateTableETags(sc.getAppName(), db, tableId, schemaETag, null);
   *

   * Although the server does not recognize this tableId, we can
   * keep our record of the ETags for the table-level files and
   * manifest. These may enable us to short-circuit the restoration
   * of the table-level files should another client be simultaneously
   * trying to restore those files to the server.
   *

   * However, we do need to delete all the instance-level files,
   * as these are tied to the schemaETag we hold, and that is now
   * invalid.
   *

   * if the local table ever had any server sync information for this
   * host then clear it. If the user changed the server URL, we have
   * already cleared this information.
   *

   * Clearing it here handles the case where an admin deleted the
   * table on the server and we are now re-pushing that table to
   * the server.
   *

   * We do not know whether the rows on the device match those on the server.
   * We will find out later, in the course of the sync.
   *

   * if (tableInstanceFilesUri != null) {
   * deleteAllSyncETagsUnderServer(sc.getAppName(), db, tableInstanceFilesUri);
   * }
   */
  @Override
  public void privilegedServerTableSchemaETagChanged(String appName, DbHandle dbHandleName,
      String tableId, String schemaETag, String tableInstanceFilesUri)
      throws ServicesAvailabilityException {

    internalUserDbInterface
        .privilegedServerTableSchemaETagChanged(appName, dbHandleName, tableId, schemaETag,
            tableInstanceFilesUri);
  }

  /**
   * Compute the app-global choiceListId for this choiceListJSON
   * and register the tuple of (choiceListId, choiceListJSON).
   * Return choiceListId.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param choiceListJSON -- the actual JSON choice list text.
   * @return choiceListId -- the unique code mapping to the choiceListJSON
   */
  @Override
  public String setChoiceList(String appName, DbHandle dbHandleName, String choiceListJSON)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.setChoiceList(appName, dbHandleName, choiceListJSON);
  }

  /**
   * Return the choice list JSON corresponding to the choiceListId
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param choiceListId -- the md5 hash of the choiceListJSON
   * @return choiceListJSON -- the actual JSON choice list text.
   */
  @Override
  public String getChoiceList(String appName, DbHandle dbHandleName, String choiceListId)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.getChoiceList(appName, dbHandleName, choiceListId);
  }

  /**
   * If the tableId is not recorded in the TableDefinition metadata table, then
   * create the tableId with the indicated columns. This will synthesize
   * reasonable metadata KVS entries for table.
   *

   * If the tableId is present, then this is a no-op.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param columns      simple transport wrapper for List<Columns>
   * @return the OrderedColumns of the user columns in the table.
   */
  @Override
  public OrderedColumns createOrOpenTableWithColumns(String appName, DbHandle dbHandleName,
      String tableId, ColumnList columns) throws ServicesAvailabilityException {

    return internalUserDbInterface
        .createOrOpenTableWithColumns(appName, dbHandleName, tableId, columns);
  }

  /**
   * If the tableId is not recorded in the TableDefinition metadata table, then
   * create the tableId with the indicated columns. And apply the supplied KVS
   * settings. If some are missing, this will synthesize reasonable metadata KVS
   * entries for table.
   *

   * If the table is present, this will delete and replace the KVS with the given KVS
   * entries if the clear flag is true
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param columns      simple transport wrapper for List<Columns>
   * @param metaData     a List<KeyValueStoreEntry>
   * @param clear        if true then delete the existing set of values for this
   *                     tableId before inserting or replacing with the new ones.
   * @return the OrderedColumns of the user columns in the table.
   */
  @Override
  public OrderedColumns createOrOpenTableWithColumnsAndProperties(String appName,
      DbHandle dbHandleName, String tableId, ColumnList columns, List<KeyValueStoreEntry> metaData,
      boolean clear) throws ServicesAvailabilityException {

    return internalUserDbInterface
        .createOrOpenTableWithColumnsAndProperties(appName, dbHandleName, tableId, columns,
            metaData, clear);
  }

  /**
   * Drop the given tableId and remove all the files (both configuration and
   * data attachments) associated with that table.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   */
  @Override
  public void deleteTableAndAllData(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {

    internalUserDbInterface.deleteTableAndAllData(appName, dbHandleName, tableId);
  }

  /**
   * Rescan the config directory tree of the given tableId and update the forms table
   * with revised information from the formDef.json files that it contains.
   *
   * @param appName
   * @param dbHandleName
   * @param tableId
   * @return true if there were no problems
   */
  @Override
  public boolean rescanTableFormDefs(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.rescanTableFormDefs(appName, dbHandleName, tableId);
  }

  /**
   * The deletion filter includes all non-null arguments. If all arguments
   * (except the db) are null, then all properties are removed.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param partition    part of the properties triplet
   * @param aspect       part of the properties triplet
   * @param key          the key of the property to be deleted
   */
  @Override
  public void deleteTableMetadata(String appName, DbHandle dbHandleName, String tableId,
      String partition, String aspect, String key) throws ServicesAvailabilityException {

    internalUserDbInterface
        .deleteTableMetadata(appName, dbHandleName, tableId, partition, aspect, key);
  }

  /**
   * Return an array of the admin columns that must be present in every database table.
   *
   * @return the list of admin columns that have to be in the table
   */
  @Override
  public String[] getAdminColumns() throws ServicesAvailabilityException {

    return internalUserDbInterface.getAdminColumns();
  }

  /**
   * Return all the columns in the given table, including any metadata columns.
   * This does a direct query against the database and is suitable for accessing
   * non-managed tables. It does not access any metadata and therefore will not
   * report non-unit-of-retention (grouping) columns.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @return the list of all columns in the table
   */
  @Override
  public String[] getAllColumnNames(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.getAllColumnNames(appName, dbHandleName, tableId);
  }

  /**
   * Return all the tableIds in the database.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @return List<String> of tableIds
   */
  @Override
  public List<String> getAllTableIds(String appName, DbHandle dbHandleName)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.getAllTableIds(appName, dbHandleName);
  }

  /**
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param partition    part of the properties triplet
   * @param aspect       part of the properties triplet
   * @param key          the key and last part of the triplet
   * @return list of KeyValueStoreEntry values matching the filter criteria
   */
  @Override
  public TableMetaDataEntries getTableMetadata(String appName, DbHandle dbHandleName,
      String tableId, String partition, String aspect, String key, String revId)
      throws ServicesAvailabilityException {

    TableMetaDataEntries entries;

    if (tableId == null) {
      // Ignore the cache, as it only caches table specific metadata
      //noinspection ConstantConditions
      entries = internalUserDbInterface
          .getTableMetadata(appName, dbHandleName, tableId, partition, aspect, key);
    } else {
      TableMetaDataEntries allEntries = getMetadata(tableId);

      if (allEntries == null) {
        // If there is no cache hit, fetch from the database
        allEntries = internalUserDbInterface
            .getTableMetadata(appName, dbHandleName, tableId, null, null, null);
        putMetadata(tableId, allEntries);
      } else {
        // If there is a cache hit, check if it is stale
        TableMetaDataEntries newEntries = internalUserDbInterface
            .getTableMetadataIfChanged(appName, dbHandleName, tableId, allEntries.getRevId());
        String newEntRevId = newEntries.getRevId();
        // We want to update the cache if the condition of the revIds being the
        // same does NOT hold
        if (!(newEntRevId != null && newEntRevId.equals(allEntries.getRevId()))) {
          putMetadata(tableId, newEntries);
          allEntries = newEntries;
        }
      }

      // Filter the requested entries from the full list
      entries = filterEntries(allEntries, partition, aspect, key);
    }

    if (entries == null) {
      // Do not return null. API is expected to return an empty list if no results are found.
      entries = new TableMetaDataEntries(tableId, null);
    }
    return entries;

  }

  /**
   * Return an array of the admin columns that should be exported to
   * a CSV file. This list excludes the SYNC_STATE and CONFLICT_TYPE columns.
   *
   * @return a list of the columns that can be exported
   */
  @Override
  public String[] getExportColumns() throws ServicesAvailabilityException {

    return internalUserDbInterface.getExportColumns();
  }

  /**
   * Get the table definition entry for a tableId. This specifies the schema
   * ETag, the data-modification ETag, and the date-time of the last successful
   * sync of the table to the server.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @return the requsted table definition entry
   */
  @Override
  public TableDefinitionEntry getTableDefinitionEntry(String appName, DbHandle dbHandleName,
      String tableId) throws ServicesAvailabilityException {

    return internalUserDbInterface.getTableDefinitionEntry(appName, dbHandleName, tableId);
  }

  /**
   * Return the list of all tables and their health status.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @return the list of TableHealthInfo records for this appName
   */
  @Override
  public List<TableHealthInfo> getTableHealthStatuses(String appName, DbHandle dbHandleName)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.getTableHealthStatuses(appName, dbHandleName);
  }

  /**
   * Retrieve the list of user-defined columns for a tableId using the metadata
   * for that table. Returns the unit-of-retention and non-unit-of-retention
   * (grouping) columns.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @return a list of the columns that the user defined
   */
  @Override
  public OrderedColumns getUserDefinedColumns(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.getUserDefinedColumns(appName, dbHandleName, tableId);
  }

  /**
   * Verifies that the tableId exists in the database.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @return true if table is listed in table definitions.
   */
  @Override
  public boolean hasTableId(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.hasTableId(appName, dbHandleName, tableId);
  }

  ////////// RAW GENERIC QUERIES ///////////

  /**
   * Get a {@link BaseTable} for this table based on the given SQL command. All
   * columns from the table are returned.
   *

   * If any of the clause parts are omitted (null), then the appropriate
   * simplified SQL statement is constructed.
   *
   * @param appName           the app name
   * @param dbHandleName      the database handle to use
   * @param tableId           the table id
   * @param whereClause       the whereClause for the selection, beginning with "WHERE". Must
   *                          include "?" instead of actual values, which are instead passed in
   *                          the selectionArgs.
   * @param bindArgs          an array of primitive values (String, Boolean, int, double) for
   *                          bind parameters
   * @param groupBy           an array of elementKeys
   * @param having            part of the query
   * @param orderByColNames   array of columns to order the results by
   * @param orderByDirections either "ASC" or "DESC", corresponding to each column name
   * @param limit             the maximum number of rows to return
   * @param offset            the index to start counting the limit from
   * @return A {@link UserTable} containing the results of the query
   */
  @Override
  public BaseTable simpleQuery(String appName, DbHandle dbHandleName, String tableId,
      String whereClause, BindArgs bindArgs, String[] groupBy, String having,
      String[] orderByColNames, String[] orderByDirections, Integer limit, Integer offset)
      throws ServicesAvailabilityException {

    SimpleQuery query = new SimpleQuery(tableId, bindArgs, whereClause, groupBy, having,
        orderByColNames, orderByDirections, limit, offset);

    BaseTable baseTable = internalUserDbInterface
        .simpleQuery(appName, dbHandleName, query.getSqlCommand(), query.getSqlBindArgs(),
            query.getSqlQueryBounds(), query.getTableId());

    baseTable.setQuery(query);

    return baseTable;
  }

  /**
   * SYNC ONLY
   *

   * Privileged version of above query.
   *

   * Get a {@link BaseTable} for this table based on the given SQL command. All
   * columns from the table are returned.
   *

   * If any of the clause parts are omitted (null), then the appropriate
   * simplified SQL statement is constructed.
   *
   * @param appName           the app name
   * @param dbHandleName      the database handle to use
   * @param tableId           the table id
   * @param whereClause       the whereClause for the selection, beginning with "WHERE". Must
   *                          include "?" instead of actual values, which are instead passed in
   *                          the selectionArgs.
   * @param bindArgs          an array of primitive values (String, Boolean, int, double) for
   *                          bind parameters
   * @param groupBy           an array of elementKeys
   * @param having            part of the query
   * @param orderByColNames   array of columns to order the results by
   * @param orderByDirections either "ASC" or "DESC", corresponding to each column name
   * @param limit             the maximum number of rows to return
   * @param offset            the index to start counting the limit from
   * @return A {@link UserTable} containing the results of the query
   */
  @Override
  public BaseTable privilegedSimpleQuery(String appName, DbHandle dbHandleName, String tableId,
      String whereClause, BindArgs bindArgs, String[] groupBy, String having,
      String[] orderByColNames, String[] orderByDirections, Integer limit, Integer offset)
      throws ServicesAvailabilityException {

    SimpleQuery query = new SimpleQuery(tableId, bindArgs, whereClause, groupBy, having,
        orderByColNames, orderByDirections, limit, offset);

    BaseTable baseTable = internalUserDbInterface
        .privilegedSimpleQuery(appName, dbHandleName, query.getSqlCommand(), query.getSqlBindArgs(),
            query.getSqlQueryBounds(), query.getTableId());

    baseTable.setQuery(query);

    return baseTable;
  }

  /**
   * Get a {@link BaseTable} for the result set of an arbitrary sql query
   * and bind parameters.
   *

   * The sql query can be arbitrarily complex and can include joins, unions, etc.
   * The data are returned as string values.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param sqlCommand   the raw sql query to execute
   * @param bindArgs     an array of primitive values (String, Boolean, int, double) for
   *                     bind parameters
   * @param limit        the maximum number of rows to return (optional)
   * @param offset       the index to start counting the limit from (optional)
   * @return An  {@link BaseTable}. Containing the results of the query
   */
  @Override
  public BaseTable arbitrarySqlQuery(String appName, DbHandle dbHandleName, String tableId,
      String sqlCommand, BindArgs bindArgs, Integer limit, Integer offset)
      throws ServicesAvailabilityException {

    ArbitraryQuery query = new ArbitraryQuery(tableId, bindArgs, sqlCommand, limit, offset);

    BaseTable baseTable = internalUserDbInterface
        .simpleQuery(appName, dbHandleName, query.getSqlCommand(), query.getSqlBindArgs(),
            query.getSqlQueryBounds(), query.getTableId());

    baseTable.setQuery(query);

    return baseTable;
  }

  /**
   * Get a {@link BaseTable} that holds the results from the continued query.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param query        The original query with the bounds adjusted
   * @return the table that contains the results for the query
   */
  @Override
  public BaseTable resumeSimpleQuery(String appName, DbHandle dbHandleName, ResumableQuery query)
      throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .simpleQuery(appName, dbHandleName, query.getSqlCommand(), query.getSqlBindArgs(),
            query.getSqlQueryBounds(), query.getTableId());

    baseTable.setQuery(query);

    return baseTable;
  }

  /**
   * SYNC ONLY
   *

   * Privileged version of above query.
   * Get a {@link BaseTable} that holds the results from the continued query.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param query        The original query with the bounds adjusted
   * @return the table that contains the results for the query
   */
  @Override
  public BaseTable resumePrivilegedSimpleQuery(String appName, DbHandle dbHandleName,
      ResumableQuery query) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .privilegedSimpleQuery(appName, dbHandleName, query.getSqlCommand(), query.getSqlBindArgs(),
            query.getSqlQueryBounds(), query.getTableId());

    baseTable.setQuery(query);

    return baseTable;
  }

  /**
   * Execute an arbitrary command with bind parameters.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param sqlCommand   the raw sql query to execute
   * @param bindArgs     an array of primitive values (String, Boolean, int, double) for
   *                     bind parameters
   */
  @Override
  public void privilegedExecute(String appName, DbHandle dbHandleName, String sqlCommand,
      BindArgs bindArgs) throws ServicesAvailabilityException {

    internalUserDbInterface.privilegedExecute(appName, dbHandleName, sqlCommand, bindArgs);
  }

  /////////// USERTABLE QUERY WRAPPERS ///////////

  /**
   * Get a {@link UserTable} for this table based on the given SQL command. All
   * columns from the table are returned.
   *

   * If any of the clause parts are omitted (null), then the appropriate
   * simplified SQL statement is constructed.
   *
   * @param appName           the app name
   * @param dbHandleName      the database handle to use
   * @param tableId           the table id
   * @param columnDefns       the columns of the result rows you want returned
   * @param whereClause       the whereClause for the selection, beginning with "WHERE". Must
   *                          include "?" instead of actual values, which are instead passed in
   *                          the selectionArgs.
   * @param bindArgs          an array of primitive values (String, Boolean, int, double) for
   *                          bind parameters
   * @param groupBy           an array of elementKeys
   * @param having            part of the sql query
   * @param orderByColNames   array of columns to order the results by
   * @param orderByDirections either "ASC" or "DESC", corresponding to each column name
   * @param limit             the maximum number of rows to return
   * @param offset            the index to start counting the limit from
   * @return A {@link UserTable} containing the results of the query
   */
  @Override
  public UserTable simpleQuery(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns columnDefns, String whereClause, BindArgs bindArgs, String[] groupBy,
      String having, String[] orderByColNames, String[] orderByDirections, Integer limit,
      Integer offset) throws ServicesAvailabilityException {

    BaseTable baseTable = simpleQuery(appName, dbHandleName, tableId, whereClause, bindArgs,
        groupBy, having, orderByColNames, orderByDirections, limit, offset);

    return new UserTable(baseTable, columnDefns, internalGetAdminColumns());
  }

  /**
   * SYNC ONLY
   *

   * Privileged version of the above query.
   * Get a {@link UserTable} for this table based on the given SQL command. All
   * columns from the table are returned.
   *

   * If any of the clause parts are omitted (null), then the appropriate
   * simplified SQL statement is constructed.
   *
   * @param appName           the app name
   * @param dbHandleName      the database handle to use
   * @param tableId           the table id
   * @param columnDefns       the columns of the result rows you want returned
   * @param whereClause       the whereClause for the selection, beginning with "WHERE". Must
   *                          include "?" instead of actual values, which are instead passed in
   *                          the selectionArgs.
   * @param bindArgs          an array of primitive values (String, Boolean, int, double) for
   *                          bind parameters
   * @param groupBy           an array of elementKeys
   * @param having            part of the sql query
   * @param orderByColNames   array of columns to order the results by
   * @param orderByDirections either "ASC" or "DESC", corresponding to each column name
   * @param limit             the maximum number of rows to return
   * @param offset            the index to start counting the limit from
   * @return A {@link UserTable} containing the results of the query
   */
  @Override
  public UserTable privilegedSimpleQuery(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns columnDefns, String whereClause, BindArgs bindArgs, String[] groupBy,
      String having, String[] orderByColNames, String[] orderByDirections, Integer limit,
      Integer offset) throws ServicesAvailabilityException {

    BaseTable baseTable = privilegedSimpleQuery(appName, dbHandleName, tableId, whereClause,
        bindArgs, groupBy, having, orderByColNames, orderByDirections, limit, offset);

    return new UserTable(baseTable, columnDefns, internalGetAdminColumns());
  }

  /**
   * Get a {@link UserTable} for the result set of an arbitrary sql query
   * and bind parameters.
   *

   * The sql query can be arbitrarily complex and can include joins, unions, etc.
   * The data are returned as string values.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param sqlCommand   the raw sql query to execute
   * @param bindArgs     an array of primitive values (String, Boolean, int, double) for
   *                     bind parameters
   * @param limit        the maximum number of rows to return
   * @param offset       the index to start counting the limit from
   * @return An  {@link BaseTable}. Containing the results of the query
   */
  @Override
  public UserTable arbitrarySqlQuery(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns columnDefns, String sqlCommand, BindArgs bindArgs, Integer limit,
      Integer offset) throws ServicesAvailabilityException {

    BaseTable baseTable = arbitrarySqlQuery(appName, dbHandleName, tableId, sqlCommand, bindArgs,
        limit, offset);

    return new UserTable(baseTable, columnDefns, internalGetAdminColumns());
  }

  /**
   * Get a {@link UserTable} that holds the results from the continued query.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param columnDefns  the columns of the result rows you want returned
   * @param query        The original query with the bounds adjusted
   * @return the results of the query in a table
   */
  @Override
  public UserTable resumeSimpleQuery(String appName, DbHandle dbHandleName,
      OrderedColumns columnDefns, ResumableQuery query) throws ServicesAvailabilityException {

    BaseTable baseTable = resumeSimpleQuery(appName, dbHandleName, query);

    return new UserTable(baseTable, columnDefns, internalGetAdminColumns());
  }

  /**
   * SYNC ONLY
   *

   * Privileged version of the above.
   * Get a {@link UserTable} that holds the results from the continued query.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param columnDefns  the columns of the result rows you want returned
   * @param query        The original query with the bounds adjusted
   * @return the results of the query in a table
   */
  @Override
  public UserTable resumePrivilegedSimpleQuery(String appName, DbHandle dbHandleName,
      OrderedColumns columnDefns, ResumableQuery query) throws ServicesAvailabilityException {

    BaseTable baseTable = resumePrivilegedSimpleQuery(appName, dbHandleName, query);

    return new UserTable(baseTable, columnDefns, internalGetAdminColumns());
  }

  /**
   * Insert or update a single table-level metadata KVS entry.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param entry        the new entry into the key value store
   */
  @Override
  public void replaceTableMetadata(String appName, DbHandle dbHandleName, KeyValueStoreEntry entry)
      throws ServicesAvailabilityException {

    internalUserDbInterface.replaceTableMetadata(appName, dbHandleName, entry);
  }

  /**
   * Insert or update a list of table-level metadata KVS entries. If clear is
   * true, then delete the existing set of values for this tableId before
   * inserting the new values.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param entries      List<KeyValueStoreEntry>
   * @param clear        if true then delete the existing set of values for this tableId
   *                     before inserting the new ones.
   */
  @Override
  public void replaceTableMetadataList(String appName, DbHandle dbHandleName, String tableId,
      List<KeyValueStoreEntry> entries, boolean clear) throws ServicesAvailabilityException {

    internalUserDbInterface
        .replaceTableMetadataList(appName, dbHandleName, tableId, entries, clear);
  }

  /**
   * Atomically delete all the fields under the given (tableId, partition, aspect)
   * and replace with the supplied values.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param partition    part of the property triplet
   * @param aspect       part of the property triplet
   * @param entries      List<KeyValueStoreEntry>
   */
  @Override
  public void replaceTableMetadataSubList(String appName, DbHandle dbHandleName, String tableId,
      String partition, String aspect, List<KeyValueStoreEntry> entries)
      throws ServicesAvailabilityException {

    internalUserDbInterface
        .replaceTableMetadataSubList(appName, dbHandleName, tableId, partition, aspect, entries);
  }

  /**
   * SYNC Only. ADMIN Privileges
   *

   * Update the schema and data-modification ETags of a given tableId.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param schemaETag   the local version of the schema
   * @param lastDataETag the local revision of the data
   */
  @Override
  public void privilegedUpdateTableETags(String appName, DbHandle dbHandleName, String tableId,
      String schemaETag, String lastDataETag) throws ServicesAvailabilityException {

    internalUserDbInterface
        .privilegedUpdateTableETags(appName, dbHandleName, tableId, schemaETag, lastDataETag);
  }

  /**
   * SYNC Only. ADMIN Privileges
   *

   * Update the timestamp of the last entirely-successful synchronization
   * attempt of this table.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   */
  @Override
  public void privilegedUpdateTableLastSyncTime(String appName, DbHandle dbHandleName,
      String tableId) throws ServicesAvailabilityException {

    internalUserDbInterface.privilegedUpdateTableLastSyncTime(appName, dbHandleName, tableId);
  }

  /**
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowId        the row id
   * @return the sync state of the row (use SyncState.valueOf() to reconstruct), or null if the
   * row does not exist.
   */
  @Override
  public String getSyncState(String appName, DbHandle dbHandleName, String tableId, String rowId)
      throws ServicesAvailabilityException {

    return internalUserDbInterface.getSyncState(appName, dbHandleName, tableId, rowId);
  }

  /**
   * SYNC Only. ADMIN Privileges!
   *

   * Update the ETag and SyncState of a given rowId. There should be exactly one
   * record for this rowId in thed database (i.e., no conflicts or checkpoints).
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowId        the row id
   * @param rowETag      the local revision of the row
   * @param syncState    - the SyncState.name()
   */
  @Override
  public void privilegedUpdateRowETagAndSyncState(String appName, DbHandle dbHandleName,
      String tableId, String rowId, String rowETag, String syncState)
      throws ServicesAvailabilityException {

    internalUserDbInterface
        .privilegedUpdateRowETagAndSyncState(appName, dbHandleName, tableId, rowId, rowETag,
            syncState);
  }

  /**
   * Return the row with the most recent changes for the given tableId and rowId.
   * If the row has conflicts, it throws an exception. Otherwise, it returns the
   * most recent checkpoint or non-checkpoint value; it will contain a single row.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns you want from the results
   * @param rowId          the row id
   * @return a table with the requested column
   */
  @Override
  public UserTable getRowsWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, String rowId) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .getRowsWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Return the row with the most recent changes for the given tableId and rowId.
   * If the row has conflicts, it throws an exception. Otherwise, it returns the
   * most recent checkpoint or non-checkpoint value; it will contain a single row.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns to return from the requested rows
   * @param rowId          the row id
   * @return the requested columns from the requested rows in a table
   */
  @Override
  public UserTable privilegedGetRowsWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, String rowId) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .privilegedGetRowsWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Return the row with the most recent changes for the given tableId and rowId.
   * If the row has conflicts, it throws an exception. Otherwise, it returns the
   * most recent checkpoint or non-checkpoint value; it will contain a single row.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns to return from the requested rows
   * @param rowId          the row id
   * @return the requested columns from the requested rows in a table
   */
  @Override
  public UserTable getMostRecentRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, String rowId) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .getMostRecentRowWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * SYNC ONLY
   *

   * Takes the row field values from a server Row (obtained through the Sync protocol)
   * and applies them to the local row (which must already exist and cannot have checkpoints).
   *

   * The outcome may delete the local row, update it to the server's values, or
   * place the local row into conflict with the server values (ending with 2 rows
   * in the database for this rowId).
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns you want from the specified rows
   * @param cvValues       the field values on the server
   * @param rowId          the row id
   * @return The rows in the database matching the rowId (may be 0, 1 or 2 rows).
   */
  @Override
  public UserTable privilegedPerhapsPlaceRowIntoConflictWithId(String appName,
      DbHandle dbHandleName, String tableId, OrderedColumns orderedColumns, ContentValues cvValues,
      String rowId) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .privilegedPerhapsPlaceRowIntoConflictWithId(appName, dbHandleName, tableId, cvValues,
            rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * SYNC, CSV Import ONLY
   *

   * Insert the given rowId with the values in the cvValues. This is data from
   * the server. All metadata values must be specified in the cvValues (even null values).
   *

   * If a row with this rowId is present, then an exception is thrown.
   *
   * @param appName              the app name
   * @param dbHandleName         the database handle to use
   * @param tableId              the table id
   * @param orderedColumns       the columns you want from the specified rows
   * @param cvValues             The values to insert into the row
   * @param rowId                the row id
   * @param asCsvRequestedChange Whether the request is from a csv import
   * @return single-row table with the content of the inserted row
   */
  @Override
  public UserTable privilegedInsertRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, ContentValues cvValues, String rowId,
      boolean asCsvRequestedChange) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .privilegedInsertRowWithId(appName, dbHandleName, tableId, cvValues, rowId,
            asCsvRequestedChange);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Inserts a checkpoint row for the given rowId in the tableId. Checkpoint
   * rows are created by ODK Survey to hold intermediate values during the
   * filling-in of the form. They act as restore points in the Survey, should
   * the application die.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns of the new row
   * @param cvValues the values you want in the new row
   * @param rowId          the row id
   * @return single-row table with the content of the inserted checkpoint
   */
  @Override
  public UserTable insertCheckpointRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, ContentValues cvValues, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .insertCheckpointRowWithId(appName, dbHandleName, tableId, cvValues, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Insert the given rowId with the values in the cvValues. If certain metadata
   * values are not specified in the cvValues, then suitable default values may
   * be supplied for them.
   *

   * If a row with this rowId and certain matching metadata fields is present,
   * then an exception is thrown.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns of the new row
   * @param cvValues the values you want in the new row
   * @param rowId          the row id
   * @return single-row table with the content of the inserted row
   */
  @Override
  public UserTable insertRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, ContentValues cvValues, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .insertRowWithId(appName, dbHandleName, tableId, cvValues, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Delete any checkpoint rows for the given rowId in the tableId. Checkpoint
   * rows are created by ODK Survey to hold intermediate values during the
   * filling-in of the form. They act as restore points in the Survey, should
   * the application die.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowId        the row id
   * @return table with the content for this rowId. May be empty.
   */
  @Override
  public UserTable deleteAllCheckpointRowsWithId(String appName, DbHandle dbHandleName,
      String tableId, OrderedColumns orderedColumns, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .deleteAllCheckpointRowsWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Delete any checkpoint rows for the given rowId in the tableId. Checkpoint
   * rows are created by ODK Survey to hold intermediate values during the
   * filling-in of the form. They act as restore points in the Survey, should
   * the application die.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns the columns to be returned from the row after resolving the checkpoint
   * @param rowId          the row id
   * @return table with the content for this rowId. May be empty.
   */
  @Override
  public UserTable deleteLastCheckpointRowWithId(String appName, DbHandle dbHandleName,
      String tableId, OrderedColumns orderedColumns, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .deleteLastCheckpointRowWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * SYNC, Conflict Resolution ONLY
   *

   * Delete the specified rowId in this tableId. This is enforcing the server
   * state on the device. I.e., the sync interaction instructed us to delete
   * this row.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns
   * @param rowId          the row id
   * @return table with the content for this rowId. May be empty. May be marked as deleted and awaiting sync
   */
  @Override
  public UserTable privilegedDeleteRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, String rowId) throws ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .privilegedDeleteRowWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Delete the specified rowId in this tableId. Deletion respects sync
   * semantics. If the row is in the SyncState.new_row state, then the row and
   * its associated file attachments are immediately deleted. Otherwise, the row
   * is placed into the SyncState.deleted state and will be retained until the
   * device can delete the record on the server.
   *

   * If you need to immediately delete a record that would otherwise sync to the
   * server, call updateRowETagAndSyncState(...) to set the row to
   * SyncState.new_row, and then call this method and it will be immediately
   * deleted (in this case, unless the record on the server was already deleted,
   * it will remain and not be deleted during any subsequent synchronizations).
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns
   * @param rowId          the row id
   * @return table with the content for this rowId. May be empty. May be marked as deleted and awaiting sync
   */
  @Override
  public UserTable deleteRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .deleteRowWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Update all rows for the given rowId to SavepointType 'INCOMPLETE' and
   * remove all but the most recent row. When used with a rowId that has
   * checkpoints, this updates to the most recent checkpoint and removes any
   * earlier checkpoints, incomplete or complete savepoints. Otherwise, it has
   * the general effect of resetting the rowId to an INCOMPLETE state.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns
   * @param rowId          the row id
   * @return single-row table with the content of the row as specified
   */
  @Override
  public UserTable saveAsIncompleteMostRecentCheckpointRowWithId(String appName,
      DbHandle dbHandleName, String tableId, OrderedColumns orderedColumns, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .saveAsIncompleteMostRecentCheckpointRowWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Update all rows for the given rowId to SavepointType 'INCOMPLETE' and
   * remove all but the most recent row. When used with a rowId that has
   * checkpoints, this updates to the most recent checkpoint and removes any
   * earlier checkpoints, incomplete or complete savepoints. Otherwise, it has
   * the general effect of resetting the rowId to an INCOMPLETE state.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns
   * @param rowId          the row id
   * @return single-row table with the content of the saved-as-incomplete row
   */
  @Override
  public UserTable saveAsCompleteMostRecentCheckpointRowWithId(String appName,
      DbHandle dbHandleName, String tableId, OrderedColumns orderedColumns, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .saveAsCompleteMostRecentCheckpointRowWithId(appName, dbHandleName, tableId, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Update the given rowId with the values in the cvValues. If certain metadata
   * values are not specified in the cvValues, then suitable default values may
   * be supplied for them. Furthermore, if the cvValues do not specify certain
   * metadata fields, then an exception may be thrown if there are more than one
   * row matching this rowId.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns
   * @param cvValues
   * @param rowId          the row id
   * @return single-row table with the content of the saved-as-incomplete row
   */
  @Override
  public UserTable updateRowWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, ContentValues cvValues, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {

    BaseTable baseTable = internalUserDbInterface
        .updateRowWithId(appName, dbHandleName, tableId, cvValues, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Client-side wrapper to make changing the row filter easier.
   *
   * @param appName        the app name
   * @param dbHandleName   the database handle to use
   * @param tableId        the table id
   * @param orderedColumns
   * @param defaultAccess
   * @param rowOwner
   * @param rowId          the row id
   * @return
   */
  @Override
  public UserTable changeRowFilterWithId(String appName, DbHandle dbHandleName, String tableId,
      OrderedColumns orderedColumns, String defaultAccess, String rowOwner, String groupReadOnly,
      String groupModify, String groupPrivileged, String rowId)
      throws IllegalArgumentException, ActionNotAuthorizedException, ServicesAvailabilityException {

    if (defaultAccess == null) {
      throw new IllegalArgumentException("defaultAccess is null");
    }
    // verify that defaultAccess is a known type
    RowFilterScope.Access.valueOf(defaultAccess);

    ContentValues cvValues = new ContentValues();
    cvValues.put(DataTableColumns.DEFAULT_ACCESS, defaultAccess);

    if (rowOwner == null) {
      cvValues.putNull(DataTableColumns.ROW_OWNER);
    } else {
      cvValues.put(DataTableColumns.ROW_OWNER, rowOwner);
    }

    if (groupReadOnly == null) {
      cvValues.putNull(DataTableColumns.GROUP_READ_ONLY);
    } else {
      cvValues.put(DataTableColumns.GROUP_READ_ONLY, groupReadOnly);
    }

    if (groupModify == null) {
      cvValues.putNull(DataTableColumns.GROUP_MODIFY);
    } else {
      cvValues.put(DataTableColumns.GROUP_MODIFY, groupModify);
    }

    if (groupPrivileged == null) {
      cvValues.putNull(DataTableColumns.GROUP_PRIVILEGED);
    } else {
      cvValues.put(DataTableColumns.GROUP_PRIVILEGED, groupPrivileged);
    }

    BaseTable baseTable = internalUserDbInterface
        .updateRowWithId(appName, dbHandleName, tableId, cvValues, rowId);

    return new UserTable(baseTable, orderedColumns, internalGetAdminColumns());
  }

  /**
   * Delete the local and server conflict records to resolve a server conflict
   *

   * A combination of primitive actions, all performed in one transaction:
   *

   * // delete the record of the server row
   * deleteServerConflictRowWithId(appName, dbHandleName, tableId, rowId);
   *

   * // move the local record into the 'new_row' sync state
   * // so it can be physically deleted.
   * updateRowETagAndSyncState(appName, dbHandleName, tableId, rowId, null,
   * SyncState.new_row.name());
   * // move the local conflict back into the normal (null) state
   * deleteRowWithId(appName, dbHandleName, tableId, rowId);
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowId        the row id
   */
  @Override
  public void resolveServerConflictWithDeleteRowWithId(String appName, DbHandle dbHandleName,
      String tableId, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {
    internalUserDbInterface
        .resolveServerConflictWithDeleteRowWithId(appName, dbHandleName, tableId, rowId);
  }

  /**
   * Resolve the server conflict by taking the local changes.
   * If the local changes are to delete this record, the record will be deleted
   * upon the next successful sync.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowId        the row id
   */
  @Override
  public void resolveServerConflictTakeLocalRowWithId(String appName, DbHandle dbHandleName,
      String tableId, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {
    internalUserDbInterface
        .resolveServerConflictTakeLocalRowWithId(appName, dbHandleName, tableId, rowId);
  }

  /**
   * Resolve the server conflict by taking the local changes plus a value map
   * of select server field values.  This map should not update any metadata
   * fields -- it should just contain user data fields.
   *

   * It is an error to call this if the local change is to delete the row.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param cvValues
   * @param rowId        the row id
   */
  @Override
  public void resolveServerConflictTakeLocalRowPlusServerDeltasWithId(String appName,
      DbHandle dbHandleName, String tableId, ContentValues cvValues, String rowId)
      throws ActionNotAuthorizedException, ServicesAvailabilityException {
    internalUserDbInterface
        .resolveServerConflictTakeLocalRowPlusServerDeltasWithId(appName, dbHandleName, tableId,
            cvValues, rowId);
  }

  /**
   * Resolve the server conflict by taking the server changes.  This may delete the local row.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   * @param rowId        the row id
   */
  @Override
  public void resolveServerConflictTakeServerRowWithId(String appName, DbHandle dbHandleName,
      String tableId, String rowId) throws ServicesAvailabilityException {
    internalUserDbInterface
        .resolveServerConflictTakeServerRowWithId(appName, dbHandleName, tableId, rowId);
  }

  /**
   * Remove app and table level manifests. Invoked when we select reset configuration
   * and the initialization task is executed.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   */
  @Override
  public void deleteAppAndTableLevelManifestSyncETags(String appName, DbHandle dbHandleName)
      throws ServicesAvailabilityException {
    internalUserDbInterface.deleteAppAndTableLevelManifestSyncETags(appName, dbHandleName);
  }

  /**
   * Forget the document ETag values for the given tableId on all servers.
   * Used when deleting a table. Exposed mainly for integration testing.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param tableId      the table id
   */
  @Override
  public void deleteAllSyncETagsForTableId(String appName, DbHandle dbHandleName, String tableId)
      throws ServicesAvailabilityException {
    internalUserDbInterface.deleteAllSyncETagsForTableId(appName, dbHandleName, tableId);
  }

  /**
   * Forget the document ETag values for everything except the specified Uri.
   * Call this when the server URI we are syncing against has changed.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param verifiedUri  (e.g., https://opendatakit-tablesdemo.appspot.com)
   */
  @Override
  public void deleteAllSyncETagsExceptForServer(String appName, DbHandle dbHandleName,
      String verifiedUri) throws ServicesAvailabilityException {
    internalUserDbInterface.deleteAllSyncETagsExceptForServer(appName, dbHandleName, verifiedUri);
  }

  /**
   * Forget the document ETag values for everything under the specified Uri.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param verifiedUri  (e.g., https://opendatakit-tablesdemo.appspot.com)
   */
  @Override
  public void deleteAllSyncETagsUnderServer(String appName, DbHandle dbHandleName,
      String verifiedUri) throws ServicesAvailabilityException {
    internalUserDbInterface.deleteAllSyncETagsUnderServer(appName, dbHandleName, verifiedUri);
  }

  /**
   * Get the document ETag values for the given file under the specified Uri.
   * The assumption is that the file system will update the modification timestamp
   * if the file has changed. This eliminates the need for computing an md5
   * hash on files that haven't changed. We can just retrieve that from the database.
   *
   * @param appName               the app name
   * @param dbHandleName          the database handle to use
   * @param verifiedUri           (e.g., https://opendatakit-tablesdemo.appspot.com)
   * @param tableId               the table id
   * @param modificationTimestamp timestamp of last file modification
   */
  @Override
  public String getFileSyncETag(String appName, DbHandle dbHandleName, String verifiedUri,
      String tableId, long modificationTimestamp) throws ServicesAvailabilityException {
    return internalUserDbInterface
        .getFileSyncETag(appName, dbHandleName, verifiedUri, tableId, modificationTimestamp);
  }

  /**
   * Get the document ETag values for the given manifest under the specified Uri.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param verifiedUri  (e.g., https://opendatakit-tablesdemo.appspot.com)
   * @param tableId      the table id
   */
  @Override
  public String getManifestSyncETag(String appName, DbHandle dbHandleName, String verifiedUri,
      String tableId) throws ServicesAvailabilityException {
    return internalUserDbInterface.getManifestSyncETag(appName, dbHandleName, verifiedUri, tableId);
  }

  /**
   * Update the document ETag values for the given file under the specified Uri.
   * The assumption is that the file system will update the modification timestamp
   * if the file has changed. This eliminates the need for computing an md5
   * hash on files that haven't changed. We can just retrieve that from the database.
   *
   * @param appName               the app name
   * @param dbHandleName          the database handle to use
   * @param verifiedUri           (e.g., https://opendatakit-tablesdemo.appspot.com)
   * @param tableId               the table id
   * @param modificationTimestamp timestamp of last file modification
   * @param eTag
   */
  @Override
  public void updateFileSyncETag(String appName, DbHandle dbHandleName, String verifiedUri,
      String tableId, long modificationTimestamp, String eTag)
      throws ServicesAvailabilityException {
    internalUserDbInterface
        .updateFileSyncETag(appName, dbHandleName, verifiedUri, tableId, modificationTimestamp,
            eTag);
  }

  /**
   * Update the document ETag values for the given manifest under the specified Uri.
   *
   * @param appName      the app name
   * @param dbHandleName the database handle to use
   * @param verifiedUri  (e.g., https://opendatakit-tablesdemo.appspot.com)
   * @param tableId      the table id
   * @param eTag
   */
  @Override
  public void updateManifestSyncETag(String appName, DbHandle dbHandleName, String verifiedUri,
      String tableId, String eTag) throws ServicesAvailabilityException {
    internalUserDbInterface
        .updateManifestSyncETag(appName, dbHandleName, verifiedUri, tableId, eTag);
  }
}


text:
- Upgrade shadow-cljs to 2.8.55

## 2.6.0 (2019-09-12)

#### Fixed

- Fix typeahead does not take external model changes into account anymore.
  See [#205](https://github.com/Day8/re-com/issues/205).

#### Changed

- Migrate to [shadow-cljs](https://shadow-cljs.github.io/docs/UsersGuide.html) and
  [lein-shadow](https://gitlab.com/nikperic/lein-shadow)


text:
package ru.mipt.acsl.geotarget;

import org.jetbrains.annotations.NotNull;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author Artem Shein
 */
public final class DateTimeUtils
{
    private static final DateTimeFormatter PARAMETER_UPDATED_FORMAT = DateTimeFormatter.ofPattern("HH:MM:ss.SS");

    @NotNull
    public static String format(@NotNull LocalDateTime localDateTime)
    {
        return localDateTime.format(PARAMETER_UPDATED_FORMAT);
    }

    private DateTimeUtils()
    {

    }
}


text:
'use strict';
// Testing to send an handle twice to the parent process.

const common = require('../common');
const assert = require('assert');
const cluster = require('cluster');
const net = require('net');

const workers = {
  toStart: 1
};

if (cluster.isMaster) {
  for (let i = 0; i < workers.toStart; ++i) {
    const worker = cluster.fork();
    worker.on('exit', common.mustCall(function(code, signal) {
      assert.strictEqual(code, 0, `Worker exited with an error code: ${code}`);
      assert.strictEqual(signal, null, `Worker exited by a signal: ${signal}`);
    }));
  }
} else {
  const server = net.createServer(common.mustCall((socket) => {
    process.send('send-handle-1', socket);
    process.send('send-handle-2', socket);
  }));

  server.listen(0, function() {
    const client = net.connect({
      host: 'localhost',
      port: server.address().port
    });
    client.on('close', common.mustCall(() => { cluster.worker.disconnect(); }));
    client.on('connect', () => { client.end(); });
  }).on('error', function(e) {
    console.error(e);
    assert.fail('server.listen failed');
  });
}


text:
create table CMEFrontMatterProviderBinding (
	front_matter integer not null references CMEFrontMatter(id) on delete cascade,
	provider integer not null references CMEProvider(id) on delete cascade,

	primary key(front_matter, provider)
);