text:
#ifndef TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_
#define TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_

#define EIGEN_USE_THREADS
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define EIGEN_USE_GPU
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_types.h"
#include "tensorflow/core/framework/variant.h"
#include "tensorflow/core/framework/variant_op_registry.h"
#include "tensorflow/core/kernels/concat_lib.h"
#include "tensorflow/core/kernels/fill_functor.h"
#include "tensorflow/core/kernels/tensor_list.h"
#include "tensorflow/core/lib/core/coding.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/refcount.h"
#include "tensorflow/core/lib/gtl/array_slice.h"
#include "tensorflow/core/platform/platform.h"
#include "tensorflow/core/util/tensor_ops_util.h"
#include "tensorflow/core/util/util.h"

// stream.h isn't available in some platforms such as Android and iOS.
// Only include it for platforms that PluggableDevice is tested on.
#if !defined(PLUGGABLE_DEVICE_SUPPORTED) &&                                \
    (__x86_64__ || __i386__ || defined(__APPLE__)) && !defined(ANDROID) && \
    !defined(__ANDROID__) && !TARGET_OS_IOS
#define PLUGGABLE_DEVICE_SUPPORTED
#endif

#ifdef PLUGGABLE_DEVICE_SUPPORTED
#include "tensorflow/stream_executor/stream.h"
#endif

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

Status TensorShapeFromTensor(const Tensor& t, PartialTensorShape* out);

Status GetElementShapeFromInput(OpKernelContext* c,
                                const TensorList& tensor_list, int index,
                                PartialTensorShape* element_shape);

Status GetInputList(OpKernelContext* c, int index, const TensorList** list);

Status ForwardInputOrCreateNewList(OpKernelContext* c, int32_t input_index,
                                   int32_t output_index,
                                   const TensorList& input_list,
                                   TensorList** output_list);

// TODO(penporn): Move this to a proper place.
inline bool IsPluggableDevice(OpKernelContext* c) {
  return c->op_device_context() && c->op_device_context()->IsPluggableDevice();
}

template <typename Device, typename T>
inline void SetZero(OpKernelContext* ctx, Tensor& tensor) {
#ifdef PLUGGABLE_DEVICE_SUPPORTED
  if (IsPluggableDevice(ctx)) {
    auto ptr =
        se::DeviceMemoryBase(tensor.flat<T>().data(), tensor.TotalBytes());
    auto stream = ctx->op_device_context()->stream();
    auto result = stream->ThenMemZero(&ptr, tensor.TotalBytes()).ok();
    DCHECK_EQ(true, result);
  } else {
#endif  // PLUGGABLE_DEVICE_SUPPORTED
    functor::SetZeroFunctor<Device, T>()(ctx->eigen_device<Device>(),
                                         tensor.flat<T>());
#ifdef PLUGGABLE_DEVICE_SUPPORTED
  }
#endif  // PLUGGABLE_DEVICE_SUPPORTED
}

template <typename T>
inline void CopyTensorPluggableDevice(OpKernelContext* ctx, Tensor& src,
                                      Tensor& dst) {
#ifdef PLUGGABLE_DEVICE_SUPPORTED
  auto src_t = src.unaligned_flat<T>();
  auto dst_t = dst.flat<T>();
  DCHECK(DataTypeCanUseMemcpy(DataTypeToEnum<T>::v()));
  auto src_ptr = se::DeviceMemoryBase(src_t.data(), src.TotalBytes());
  auto dst_ptr = se::DeviceMemoryBase(dst_t.data(), dst.TotalBytes());
  auto stream = ctx->op_device_context()->stream();
  auto result = stream->ThenMemcpy(&dst_ptr, src_ptr, src.TotalBytes()).ok();
  DCHECK_EQ(true, result);
#else
  LOG(FATAL)  // Crash OK.
      << "PluggableDevice is not supported on this platform.";
#endif  // PLUGGABLE_DEVICE_SUPPORTED
}

template <typename Device, typename T>
inline void CopyTensor(OpKernelContext* ctx, Tensor& src, Tensor& dst) {
  auto src_t = src.unaligned_flat<T>();
  auto dst_t = dst.flat<T>();
  dst_t.device(ctx->eigen_device<Device>()) = src_t;
}

template <typename T>
void ConcatPluggableDevice(
    OpKernelContext* context,
    const std::vector<std::unique_ptr<typename TTypes<T, 2>::ConstMatrix>>&
        inputs,
    typename TTypes<T, 2>::Matrix* output) {
#ifdef PLUGGABLE_DEVICE_SUPPORTED
  DCHECK(DataTypeCanUseMemcpy(DataTypeToEnum<T>::v()));

  se::Stream* stream = context->op_device_context()->stream();

  size_t num_inputs = inputs.size();
  std::vector<ptrdiff_t> sizes;
  sizes.reserve(num_inputs);
  int64 row_size = 0;
  for (const auto& input : inputs) {
    sizes.push_back(input->dimension(1));
    row_size += sizes.back();
  }

  T* out = &(*output)(0, 0);
  std::vector<const T*> inp;
  inp.reserve(num_inputs);
  for (const auto& input : inputs) {
    inp.push_back(&(*input)(0, 0));
  }
  const int64 dim0 = output->dimension(0);
  for (int64 i = 0; i < dim0; ++i) {
    for (int64 j = 0; j < num_inputs; ++j) {
      auto size = sizes[j];
      se::DeviceMemoryBase out_base{out, size * sizeof(T)};
      se::DeviceMemoryBase inp_base{const_cast<T*>(inp[j]), size * sizeof(T)};
      stream->ThenMemcpy(&out_base, inp_base, size * sizeof(T));
      out += size;
      inp[j] += size;
    }
  }
#else
  LOG(FATAL)  // Crash OK.
      << "PluggableDevice is not supported on this platform.";
#endif  // PLUGGABLE_DEVICE_SUPPORTED
}

template <typename Device, typename T>
class TensorListStack : public OpKernel {
 public:
  typedef std::vector<std::unique_ptr<typename TTypes<T, 2>::ConstMatrix>>
      ConstMatrixVector;
  explicit TensorListStack(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_));
    OP_REQUIRES_OK(c, c->GetAttr("num_elements", &num_elements_));
  }

  void Compute(OpKernelContext* c) override {
    const TensorList* tensor_list = nullptr;
    OP_REQUIRES_OK(c, GetInputList(c, 0, &tensor_list));
    OP_REQUIRES(
        c, element_dtype_ == tensor_list->element_dtype,
        errors::InvalidArgument(
            "Invalid data types; op elements ", DataTypeString(element_dtype_),
            " but list elements ", DataTypeString(tensor_list->element_dtype)));
    if (num_elements_ != -1) {
      OP_REQUIRES(c, tensor_list->tensors().size() == num_elements_,
                  errors::InvalidArgument(
                      "Operation expected a list with ", num_elements_,
                      " elements but got a list with ",
                      tensor_list->tensors().size(), " elements."));
    }
    PartialTensorShape partial_element_shape;
    OP_REQUIRES_OK(c, GetElementShapeFromInput(c, *tensor_list, 1,
                                               &partial_element_shape));
    OP_REQUIRES(
        c,
        partial_element_shape.IsFullyDefined() ||
            !tensor_list->tensors().empty(),
        errors::InvalidArgument("Tried to stack elements of an empty ",
                                "list with non-fully-defined element_shape: ",
                                partial_element_shape.DebugString()));

    // Check that `element_shape` input tensor is compatible with the shapes of
    // element tensors.
    if (!tensor_list->element_shape.IsFullyDefined()) {
      for (int i = 0; i < tensor_list->tensors().size(); ++i) {
        const Tensor& t = tensor_list->tensors()[i];
        if (t.dtype() != DT_INVALID) {
          PartialTensorShape tmp = partial_element_shape;
          OP_REQUIRES_OK(c, tmp.MergeWith(t.shape(), &partial_element_shape));
        }
      }
    }

    // Compute the shape of the output tensor by pre-pending the leading dim to
    // the element_shape.
    TensorShape element_shape;
    OP_REQUIRES(c, partial_element_shape.AsTensorShape(&element_shape),
                errors::InvalidArgument(
                    "Tried to stack list which only contains uninitialized ",
                    "tensors and has a non-fully-defined element_shape: ",
                    partial_element_shape.DebugString()));
    TensorShape output_shape = element_shape;
    output_shape.InsertDim(0, tensor_list->tensors().size());
    Tensor* output;
    OP_REQUIRES_OK(c, c->allocate_output(0, output_shape, &output));
    if (output->NumElements() == 0) {
      return;
    }

    ConstMatrixVector inputs_flat;
    inputs_flat.reserve(tensor_list->tensors().size());
    Tensor zeros;
    for (const auto& t : tensor_list->tensors()) {
      if (t.dtype() != DT_INVALID) {
        inputs_flat.emplace_back(new typename TTypes<T, 2>::ConstMatrix(
            t.shaped<T, 2>({1, t.NumElements()})));
      } else {
        if (!zeros.NumElements()) {
          AllocatorAttributes attr;
          if (element_dtype_ == DT_VARIANT) {
            attr.set_on_host(true);
          }
          OP_REQUIRES_OK(
              c, c->allocate_temp(element_dtype_, element_shape, &zeros, attr));
          SetZero<Device, T>(c, zeros);
        }
        inputs_flat.emplace_back(new typename TTypes<T, 2>::ConstMatrix(
            const_cast<const Tensor&>(zeros).shaped<T, 2>(
                {1, zeros.NumElements()})));
      }
    }
    auto output_flat = output->shaped<T, 2>({1, output->NumElements()});

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
    if (std::is_same<Device, Eigen::GpuDevice>::value) {
      ConcatGPU<T>(c, inputs_flat, output, &output_flat);
      return;
    }
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
    if (IsPluggableDevice(c)) {
      ConcatPluggableDevice<T>(c, inputs_flat, &output_flat);
    } else {
      ConcatCPU<T>(c->device(), inputs_flat, &output_flat);
    }
  }

 private:
  int num_elements_;
  DataType element_dtype_;
};

template <typename Device, typename T>
class TensorListGetItem : public OpKernel {
 public:
  explicit TensorListGetItem(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_));
  }

  void Compute(OpKernelContext* c) override {
    const TensorList* l = nullptr;
    OP_REQUIRES_OK(c, GetInputList(c, 0, &l));
    OP_REQUIRES(c, element_dtype_ == l->element_dtype,
                errors::InvalidArgument("Invalid data types; op elements ",
                                        DataTypeString(element_dtype_),
                                        " but list elements ",
                                        DataTypeString(l->element_dtype)));
    int32_t index = c->input(1).scalar<int32>()();
    OP_REQUIRES(c, index < l->tensors().size(),
                errors::InvalidArgument("Trying to access element ", index,
                                        " in a list with ", l->tensors().size(),
                                        " elements."));
    if (l->tensors()[index].dtype() != DT_INVALID) {
      c->set_output(0, l->tensors()[index]);
    } else {
      PartialTensorShape partial_element_shape;
      OP_REQUIRES_OK(
          c, GetElementShapeFromInput(c, *l, 2, &partial_element_shape));
      TensorShape element_shape;
      // If l->element_shape and the element_shape input are both not fully
      // defined, try to infer the shape from other list elements. This requires
      // that all initialized list elements have the same shape.
      // NOTE(srbs): This might be a performance bottleneck since we are
      // iterating over the entire list here. This is necessary for feature
      // parity with TensorArray.read. TensorArray has a mode in which all
      // elements are required to be of the same shape, TensorList does not.
      // In that mode TensorArray sets the array's element_shape on the first
      // write call. We could do something similar here if needed.
      if (!partial_element_shape.IsFullyDefined()) {
        for (const Tensor& t : l->tensors()) {
          if (t.dtype() != DT_INVALID) {
            PartialTensorShape tmp = partial_element_shape;
            OP_REQUIRES_OK(c, tmp.MergeWith(t.shape(), &partial_element_shape));
          }
        }
      }
      OP_REQUIRES(
          c, partial_element_shape.AsTensorShape(&element_shape),
          errors::InvalidArgument("Trying to read an uninitialized tensor but ",
                                  "element_shape is not fully defined: ",
                                  partial_element_shape.DebugString(),
                                  " and no list element is set."));
      Tensor* result;
      AllocatorAttributes attr;
      if (element_dtype_ == DT_VARIANT) {
        attr.set_on_host(true);
      }
      OP_REQUIRES_OK(c, c->allocate_output(0, element_shape, &result, attr));
      SetZero<Device, T>(c, *result);
    }
  }

 private:
  DataType element_dtype_;
};

template <typename Device, typename T>
class TensorListPopBack : public OpKernel {
 public:
  explicit TensorListPopBack(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_));
  }

  void Compute(OpKernelContext* c) override {
    const TensorList* l = nullptr;
    OP_REQUIRES_OK(c, GetInputList(c, 0, &l));
    OP_REQUIRES(c, element_dtype_ == l->element_dtype,
                errors::InvalidArgument("Invalid data types; op elements ",
                                        DataTypeString(element_dtype_),
                                        " but list elements ",
                                        DataTypeString(l->element_dtype)));

    OP_REQUIRES(c, !l->tensors().empty(),
                errors::InvalidArgument("Trying to pop from an empty list."));

    const Tensor& t = l->tensors().back();
    if (t.dtype() != DT_INVALID) {
      c->set_output(1, t);
    } else {
      PartialTensorShape partial_element_shape;
      OP_REQUIRES_OK(
          c, GetElementShapeFromInput(c, *l, 1, &partial_element_shape));
      TensorShape element_shape;
      OP_REQUIRES(
          c, partial_element_shape.AsTensorShape(&element_shape),
          errors::InvalidArgument("Trying to read an uninitialized tensor but ",
                                  "element_shape is not fully defined.",
                                  partial_element_shape.DebugString()));
      Tensor* result;
      AllocatorAttributes attr;
      if (element_dtype_ == DT_VARIANT) {
        attr.set_on_host(true);
      }
      OP_REQUIRES_OK(c, c->allocate_output(1, element_shape, &result, attr));
      SetZero<Device, T>(c, *result);
    }

    TensorList* output_list = nullptr;
    OP_REQUIRES_OK(c, ForwardInputOrCreateNewList(c, 0, 0, *l, &output_list));
    output_list->tensors().pop_back();
  }

 private:
  DataType element_dtype_;
};

template <typename Device, typename T>
class TensorListConcat : public OpKernel {
 public:
  using ConstMatrixVector =
      std::vector<std::unique_ptr<typename TTypes<T, 2>::ConstMatrix>>;
  explicit TensorListConcat(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_));
    if (c->HasAttr("element_shape")) {
      OP_REQUIRES_OK(c, c->GetAttr("element_shape", &element_shape_));
    }
  }

  void Compute(OpKernelContext* c) override {
    PartialTensorShape element_shape_except_first_dim;
    if (!element_shape_.unknown_rank()) {
      element_shape_except_first_dim = PartialTensorShape(
          gtl::ArraySlice<int64_t>(element_shape_.dim_sizes()).subspan(1));
    }
    // Check that the input Variant tensor is indeed a TensorList and has the
    // correct element type.
    const TensorList* tensor_list = nullptr;
    OP_REQUIRES_OK(c, GetInputList(c, 0, &tensor_list));
    OP_REQUIRES(
        c, element_dtype_ == tensor_list->element_dtype,
        errors::InvalidArgument(
            "Invalid data types; op elements ", DataTypeString(element_dtype_),
            " but list elements ", DataTypeString(tensor_list->element_dtype)));
    // The leading dimension of all list elements if they are all the same.
    // This is used as the leading dim of uninitialized tensors in the list
    // if leading_dims is not provided.
    int64_t first_dim = -1;
    if (c->num_inputs() > 1) {
      // TensorListConcatV2
      PartialTensorShape element_shape;
      OP_REQUIRES_OK(
          c, GetElementShapeFromInput(c, *tensor_list, 1, &element_shape));
      OP_REQUIRES(c, element_shape.unknown_rank() || element_shape.dims() >= 1,
                  errors::InvalidArgument(
                      "Concat requires elements to be at least vectors, ",
                      "found scalars instead."));
      // Split `element_shape` into `first_dim` and
      // `element_shape_except_first_dim`.
      first_dim = element_shape.dim_size(0);
      element_shape_except_first_dim = element_shape;
      element_shape_except_first_dim.RemoveDim(0);
    }
    // If the TensorList is empty, element_shape_except_first_dim must be fully
    // defined.
    OP_REQUIRES(c,
                !tensor_list->tensors().empty() ||
                    element_shape_except_first_dim.IsFullyDefined(),
                errors::InvalidArgument(
                    "All except the first dimension must be fully defined ",
                    "when concating an empty tensor list. element_shape: ",
                    element_shape_except_first_dim.DebugString()));
    // 1. Check that `element_shape_except_first_dim` input tensor is
    //    compatible with the shapes of element tensors.
    // 2. Check that the elements have the same shape except the first dim.
    // 3. If `first_dim` is known, check that it is compatible with the leading
    //    dims of all elements.
    // 4. If `first_dim` is unknown (-1), check whether all initialized
    //    elements have the same leading dim and if so set `first_dim` to that
    //    value.
    if (!tensor_list->element_shape.IsFullyDefined()) {
      bool check_dim = (first_dim == -1);
      int64_t inferred_first_dim = first_dim;
      for (int i = 0; i < tensor_list->tensors().size(); ++i) {
        const Tensor& t = tensor_list->tensors()[i];
        if (t.dtype() != DT_INVALID) {
          PartialTensorShape tmp = element_shape_except_first_dim;
          OP_REQUIRES(
              c, TensorShapeUtils::IsVectorOrHigher(t.shape()),
              errors::InvalidArgument("Concat saw a scalar shape at index ", i,
                                      " but requires at least vectors."));
          TensorShape shape_except_first_dim = TensorShape(
              gtl::ArraySlice<int64_t>(t.shape().dim_sizes()).subspan(1));
          OP_REQUIRES_OK(c, tmp.MergeWith(shape_except_first_dim,
                                          &element_shape_except_first_dim));
          OP_REQUIRES(c, first_dim == -1 || first_dim == t.shape().dim_size(0),
                      errors::InvalidArgument(
                          "First entry of element_shape input does not match ",
                          "the first dim of list element at index: ", i,
                          " Expected: ", first_dim,
                          " Actual: ", t.shape().dim_size(0)));
          if (check_dim) {
            if (inferred_first_dim == -1) {
              inferred_first_dim = t.shape().dim_size(0);
            } else if (inferred_first_dim != t.shape().dim_size(0)) {
              inferred_first_dim = -1;
              check_dim = false;
            }
          }
        }
      }
      first_dim = inferred_first_dim;
    }
    TensorShape output_shape;
    OP_REQUIRES(c, element_shape_except_first_dim.AsTensorShape(&output_shape),
                errors::InvalidArgument(
                    "Trying to concat list with only uninitialized tensors ",
                    "but element_shape_except_first_dim is not fully defined: ",
                    element_shape_except_first_dim.DebugString()));
    // Build the lengths_tensor and leading dim of the output tensor by
    // iterating over all element tensors.
    Tensor* lengths_tensor = nullptr;
    OP_REQUIRES_OK(c, c->allocate_output(1,
                                         TensorShape({static_cast<int64_t>(
                                             tensor_list->tensors().size())}),
                                         &lengths_tensor));
    auto lengths_tensor_vec = lengths_tensor->vec<int64_t>();
    int64_t leading_dim = 0;
    for (size_t i = 0; i < tensor_list->tensors().size(); i++) {
      int64_t dim;
      if (tensor_list->tensors()[i].dtype() != DT_INVALID) {
        dim = tensor_list->tensors()[i].shape().dim_size(0);
      } else {
        // If leading_dims is not provided or does not contain an entry for
        // index i use the inferred `first_dim` if set.
        if ((c->num_inputs() <= 2 || i >= c->input(2).NumElements()) &&
            first_dim != -1) {
          dim = first_dim;
        } else {
          OP_REQUIRES(c, c->num_inputs() > 2,
                      errors::InvalidArgument(
                          "Concating lists with uninitialized tensors is not ",
                          "supported in this version of TensorListConcat. ",
                          "Consider updating your GraphDef to run the newer ",
                          "version."));
          OP_REQUIRES(c, i < c->input(2).NumElements(),
                      errors::InvalidArgument(
                          "List contains uninitialized tensor at index ", i,
                          " but leading_dims has only ",
                          c->input(2).NumElements(), " elements."));
          dim = c->input(2).vec<int64_t>()(i);
        }
      }
      leading_dim += dim;
      lengths_tensor_vec(i) = dim;
    }
    output_shape.InsertDim(0, leading_dim);
    Tensor* output;
    // Allocate the output tensor and fill it up with the concated element
    // tensors.
    OP_REQUIRES_OK(c, c->allocate_output(0, output_shape, &output));
    if (output->NumElements() == 0) {
      return;
    }

    ConstMatrixVector inputs_flat;
    inputs_flat.reserve(tensor_list->tensors().size());
    // Store the zeros tensors in a vector to prevent them from being GC'ed till
    // concat is complete.
    std::vector<Tensor> zeros_vec;
    for (int i = 0; i < tensor_list->tensors().size(); i++) {
      const Tensor& element_tensor = tensor_list->tensors()[i];
      if (element_tensor.dtype() != DT_INVALID) {
        if (element_tensor.NumElements() > 0) {
          inputs_flat.emplace_back(new typename TTypes<T, 2>::ConstMatrix(
              element_tensor.shaped<T, 2>({1, element_tensor.NumElements()})));
        }
      } else {
        AllocatorAttributes attr;
        if (element_dtype_ == DT_VARIANT) {
          attr.set_on_host(true);
        }
        TensorShape element_shape = output_shape;
        element_shape.set_dim(0, lengths_tensor_vec(i));
        zeros_vec.emplace_back();
        Tensor& zeros = zeros_vec.back();
        OP_REQUIRES_OK(
            c, c->allocate_temp(element_dtype_, element_shape, &zeros, attr));
        SetZero<Device, T>(c, zeros);
        inputs_flat.emplace_back(new typename TTypes<T, 2>::ConstMatrix(
            const_cast<const Tensor&>(zeros).shaped<T, 2>(
                {1, zeros.NumElements()})));
      }
    }
    auto output_flat = output->shaped<T, 2>({1, output->NumElements()});

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
    if (std::is_same<Device, Eigen::GpuDevice>::value) {
      ConcatGPU<T>(c, inputs_flat, output, &output_flat);
      return;
    }
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
    if (IsPluggableDevice(c)) {
      ConcatPluggableDevice<T>(c, inputs_flat, &output_flat);
    } else {
      ConcatCPU<T>(c->device(), inputs_flat, &output_flat);
    }
  }

 private:
  DataType element_dtype_;
  PartialTensorShape element_shape_;
};

template <typename Device, typename T>
class TensorListSplit : public OpKernel {
 public:
  TensorListSplit(OpKernelConstruction* c) : OpKernel(c) {}

  void Compute(OpKernelContext* c) override {
    Tensor* output_tensor;
    AllocatorAttributes attr;
    attr.set_on_host(true);
    OP_REQUIRES_OK(c, c->allocate_output(0, {}, &output_tensor, attr));
    PartialTensorShape element_shape;
    OP_REQUIRES_OK(c, TensorShapeFromTensor(c->input(1), &element_shape));
    OP_REQUIRES(c, element_shape.unknown_rank() || element_shape.dims() >= 1,
                errors::InvalidArgument(
                    "TensorListSplit requires element_shape to be at least of ",
                    "rank 1, but saw: ", element_shape.DebugString()));
    TensorList output_list;
    const Tensor& input_tensor = c->input(0);
    output_list.element_dtype = input_tensor.dtype();
    OP_REQUIRES(c, TensorShapeUtils::IsVectorOrHigher(input_tensor.shape()),
                errors::InvalidArgument(
                    "Tensor must be at least a vector, but saw shape: ",
                    input_tensor.shape().DebugString()));
    TensorShape tensor_shape_without_first_dim(input_tensor.shape());
    tensor_shape_without_first_dim.RemoveDim(0);
    PartialTensorShape element_shape_without_first_dim;
    if (!element_shape.unknown_rank()) {
      element_shape_without_first_dim =
          PartialTensorShape(element_shape.dim_sizes());
      element_shape_without_first_dim.RemoveDim(0);
    }
    OP_REQUIRES(c,
                element_shape_without_first_dim.IsCompatibleWith(
                    tensor_shape_without_first_dim),
                errors::InvalidArgument(
                    "tensor shape ", input_tensor.shape().DebugString(),
                    " is not compatible with element_shape ",
                    element_shape.DebugString()));
    output_list.element_shape = element_shape;
    const Tensor& lengths = c->input(2);
    OP_REQUIRES(c, TensorShapeUtils::IsVector(lengths.shape()),
                errors::InvalidArgument(
                    "Expected lengths to be a vector, received shape: ",
                    lengths.shape().DebugString()));
    output_list.tensors().reserve(lengths.shape().dim_size(0));

    const auto copy_tensor = IsPluggableDevice(c)
                                 ? &CopyTensorPluggableDevice<T>
                                 : &CopyTensor<Device, T>;

    int64_t start = 0;
    int64_t end = 0;
    for (int i = 0; i < lengths.shape().dim_size(0); ++i) {
      int64_t length = lengths.vec<int64_t>()(i);
      OP_REQUIRES(
          c, length >= 0,
          errors::InvalidArgument("Invalid value in lengths: ", length));
      end = start + length;
      OP_REQUIRES(c, end <= input_tensor.shape().dim_size(0),
                  errors::InvalidArgument("Attempting to slice [", start, ", ",
                                          end, "] from tensor with length ",
                                          input_tensor.shape().dim_size(0)));
      Tensor tmp = input_tensor.Slice(start, end);
      start = end;
      // TODO(apassos) maybe not always align; but weird compiler bugs seem to
      // prevent this.
      Tensor aligned;
      OP_REQUIRES_OK(c, c->allocate_temp(tmp.dtype(), tmp.shape(), &aligned));
      copy_tensor(c, tmp, aligned);
      output_list.tensors().emplace_back(aligned);
    }
    OP_REQUIRES(c, end == input_tensor.shape().dim_size(0),
                errors::InvalidArgument(
                    "Unused values in tensor. Length of tensor: ",
                    input_tensor.shape().dim_size(0), " Values used: ", end));
    output_tensor->scalar<Variant>()() = std::move(output_list);
  }
};

template <typename Device, typename T>
class TensorListGather : public OpKernel {
 public:
  typedef std::vector<std::unique_ptr<typename TTypes<T, 2>::ConstMatrix>>
      ConstMatrixVector;
  explicit TensorListGather(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_));
  }

  void Compute(OpKernelContext* c) override {
    const TensorList* tensor_list = nullptr;
    OP_REQUIRES_OK(c, GetInputList(c, 0, &tensor_list));
    OP_REQUIRES(
        c, element_dtype_ == tensor_list->element_dtype,
        errors::InvalidArgument(
            "Invalid data types; op elements ", DataTypeString(element_dtype_),
            " but list elements ", DataTypeString(tensor_list->element_dtype)));
    const Tensor& indices = c->input(1);
    PartialTensorShape partial_element_shape;
    OP_REQUIRES_OK(c, GetElementShapeFromInput(c, *tensor_list, 2,
                                               &partial_element_shape));
    OP_REQUIRES(
        c, partial_element_shape.IsFullyDefined() || indices.NumElements() > 0,
        errors::InvalidArgument("Tried to gather 0-elements from "
                                "a list with non-fully-defined shape: ",
                                partial_element_shape.DebugString()));

    // Check that `element_shape` input tensor is compatible with the shapes of
    // element tensors.
    if (!tensor_list->element_shape.IsFullyDefined()) {
      for (int index = 0; index < indices.NumElements(); ++index) {
        const int i = indices.flat<int32>()(index);
        const Tensor& t = tensor_list->tensors()[i];
        if (t.dtype() != DT_INVALID) {
          PartialTensorShape tmp = partial_element_shape;
          OP_REQUIRES_OK(c, tmp.MergeWith(t.shape(), &partial_element_shape));
        }
      }
    }

    // Compute the shape of the output tensor by pre-pending the leading dim to
    // the element_shape.
    TensorShape element_shape;
    OP_REQUIRES(
        c, partial_element_shape.AsTensorShape(&element_shape),
        errors::InvalidArgument("Tried to gather uninitialized tensors from a ",
                                "list with non-fully-defined element_shape: ",
                                partial_element_shape.DebugString()));
    TensorShape output_shape = element_shape;
    output_shape.InsertDim(0, indices.NumElements());
    Tensor* output;
    OP_REQUIRES_OK(c, c->allocate_output(0, output_shape, &output));
    if (output->NumElements() == 0) {
      return;
    }

    ConstMatrixVector inputs_flat;
    inputs_flat.reserve(indices.NumElements());
    Tensor zeros;
    for (int index = 0; index < indices.NumElements(); ++index) {
      const int i = indices.flat<int32>()(index);
      OP_REQUIRES(
          c, i < tensor_list->tensors().size(),
          errors::InvalidArgument("Index ", i, " out o range; list only has ",
                                  tensor_list->tensors().size(), " elements."));
      const Tensor& t = tensor_list->tensors()[i];
      if (t.dtype() != DT_INVALID) {
        inputs_flat.emplace_back(new typename TTypes<T, 2>::ConstMatrix(
            t.shaped<T, 2>({1, t.NumElements()})));
      } else {
        if (!zeros.NumElements()) {
          AllocatorAttributes attr;
          if (element_dtype_ == DT_VARIANT) {
            attr.set_on_host(true);
          }
          OP_REQUIRES_OK(
              c, c->allocate_temp(element_dtype_, element_shape, &zeros, attr));
          SetZero<Device, T>(c, zeros);
        }
        inputs_flat.emplace_back(new typename TTypes<T, 2>::ConstMatrix(
            const_cast<const Tensor&>(zeros).shaped<T, 2>(
                {1, zeros.NumElements()})));
      }
    }
    auto output_flat = output->shaped<T, 2>({1, output->NumElements()});

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
    if (std::is_same<Device, Eigen::GpuDevice>::value) {
      ConcatGPU<T>(c, inputs_flat, output, &output_flat);
      return;
    }
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
    if (IsPluggableDevice(c)) {
      ConcatPluggableDevice<T>(c, inputs_flat, &output_flat);
    } else {
      ConcatCPU<T>(c->device(), inputs_flat, &output_flat);
    }
  }

 private:
  DataType element_dtype_;
};

template <typename Device, typename T>
class TensorListFromTensor : public OpKernel {
 public:
  TensorListFromTensor(OpKernelConstruction* c) : OpKernel(c) {}

  void Compute(OpKernelContext* c) override {
    Tensor* output_tensor;
    AllocatorAttributes attr;
    attr.set_on_host(true);
    OP_REQUIRES_OK(c, c->allocate_output(0, {}, &output_tensor, attr));
    PartialTensorShape element_shape;
    OP_REQUIRES_OK(c, TensorShapeFromTensor(c->input(1), &element_shape));
    TensorList output_list;
    const Tensor& t = c->input(0);
    output_list.element_dtype = t.dtype();
    OP_REQUIRES(c, TensorShapeUtils::IsVectorOrHigher(t.shape()),
                errors::InvalidArgument(
                    "Tensor must be at least a vector, but saw shape: ",
                    t.shape().DebugString()));
    TensorShape output_shape(t.shape());
    output_shape.RemoveDim(0);
    OP_REQUIRES(c, element_shape.IsCompatibleWith(output_shape),
                errors::InvalidArgument(
                    "Specified a list with shape ", element_shape.DebugString(),
                    " from a tensor with shape ", output_shape.DebugString()));
    output_list.element_shape = element_shape;
    output_list.tensors().reserve(t.shape().dim_size(0));

    const auto copy_tensor = IsPluggableDevice(c)
                                 ? &CopyTensorPluggableDevice<T>
                                 : &CopyTensor<Device, T>;

    for (int i = 0; i < t.shape().dim_size(0); ++i) {
      Tensor tmp = t.Slice(i, i + 1);
      TensorShape tmp_shape = tmp.shape();
      tmp_shape.RemoveDim(0);
      OP_REQUIRES(c, tmp.CopyFrom(tmp, tmp_shape),
                  errors::Unknown("Unexpected shape error."));
      // TODO(apassos) maybe not always align; but weird compiler bugs seem to
      // prevent this.
      Tensor aligned;
      OP_REQUIRES_OK(c, c->allocate_temp(tmp.dtype(), tmp.shape(), &aligned));
      copy_tensor(c, tmp, aligned);
      output_list.tensors().push_back(aligned);
    }
    output_tensor->scalar<Variant>()() = std::move(output_list);
  }
};

// Scatters values in `value` into `list`. Assumes that `indices` are valid.
template <typename Device, typename T>
Status Scatter(OpKernelContext* c, const Tensor& value, const Tensor& indices,
               TensorList* list) {
  const auto copy_tensor = IsPluggableDevice(c) ? &CopyTensorPluggableDevice<T>
                                                : &CopyTensor<Device, T>;
  for (int index = 0; index < indices.NumElements(); ++index) {
    const int i = indices.flat<int32>()(index);
    Tensor tmp = value.Slice(index, index + 1);
    TensorShape tmp_shape = tmp.shape();
    tmp_shape.RemoveDim(0);
    if (!tmp.CopyFrom(tmp, tmp_shape)) {
      return errors::Unknown("Unexpected shape error.");
    }
    // TODO(apassos) maybe not always align; but weird compiler bugs seem to
    // prevent this.
    Tensor aligned;
    TF_RETURN_IF_ERROR(c->allocate_temp(tmp.dtype(), tmp.shape(), &aligned));
    // TODO(apassos) do all slices in a single kernel invocation instead of
    // many small ones.
    copy_tensor(c, tmp, aligned);
    std::swap(list->tensors()[i], aligned);
  }
  return Status::OK();
}

template <typename Device, typename T>
class TensorListScatterIntoExistingList : public OpKernel {
 public:
  TensorListScatterIntoExistingList(OpKernelConstruction* c) : OpKernel(c) {}

  void Compute(OpKernelContext* c) override {
    const TensorList* l = nullptr;
    OP_REQUIRES_OK(c, GetInputList(c, 0, &l));
    const Tensor& input_tensor = c->input(1);
    const Tensor& indices = c->input(2);

    // Check that inputs are valid.
    OP_REQUIRES(c, input_tensor.dtype() == l->element_dtype,
                errors::InvalidArgument(
                    "Invalid data types; input tensor type: ",
                    DataTypeString(input_tensor.dtype()),
                    " list element_type: ", DataTypeString(l->element_dtype)));
    OP_REQUIRES(c, TensorShapeUtils::IsVectorOrHigher(input_tensor.shape()),
                errors::InvalidArgument(
                    "Tensor must be at least a vector, but saw shape: ",
                    input_tensor.shape().DebugString()));
    OP_REQUIRES(c, TensorShapeUtils::IsVector(indices.shape()),
                errors::InvalidArgument(
                    "Expected indices to be a vector, but received shape: ",
                    indices.shape().DebugString()));
    OP_REQUIRES(
        c, indices.NumElements() == input_tensor.shape().dim_size(0),
        errors::InvalidArgument(
            "Expected len(indices) == tensor.shape[0], but saw: ",
            indices.NumElements(), " vs. ", input_tensor.shape().dim_size(0)));

    // Resize the list if needed to accommodate all indices.
    TensorList* output_list = nullptr;
    OP_REQUIRES_OK(c, ForwardInputOrCreateNewList(c, 0, 0, *l, &output_list));
    const auto indices_vec = indices.vec<int32>();
    int32_t max_index =
        (indices.NumElements() == 0)
            ? -1
            : *std::max_element(indices_vec.data(),
                                indices_vec.data() + indices.NumElements());
    if (max_index + 1 > output_list->tensors().size()) {
      output_list->tensors().resize(max_index + 1);
    }

    // Scatter the values.
    OP_REQUIRES_OK(c,
                   Scatter<Device, T>(c, input_tensor, indices, output_list));
  }
};

template <typename Device, typename T>
class TensorListScatter : public OpKernel {
 public:
  TensorListScatter(OpKernelConstruction* c) : OpKernel(c) {}

  void Compute(OpKernelContext* c) override {
    Tensor* output_tensor;
    AllocatorAttributes attr;
    attr.set_on_host(true);
    OP_REQUIRES_OK(c, c->allocate_output(0, {}, &output_tensor, attr));
    Tensor indices = c->input(1);
    PartialTensorShape element_shape;
    OP_REQUIRES_OK(c, TensorShapeFromTensor(c->input(2), &element_shape));
    // TensorListScatterV2 passes the num_elements input, TensorListScatter does
    // not.
    int num_elements = c->num_inputs() >= 4 ? c->input(3).scalar<int>()() : -1;
    OP_REQUIRES(c, num_elements >= -1,
                errors::InvalidArgument(
                    "TensorListScatter expects num_elements >= -1, found: ",
                    num_elements));
    TensorList output_list;
    const Tensor& input_tensor = c->input(0);
    output_list.element_dtype = input_tensor.dtype();
    OP_REQUIRES(c, TensorShapeUtils::IsVectorOrHigher(input_tensor.shape()),
                errors::InvalidArgument(
                    "Tensor must be at least a vector, but saw shape: ",
                    input_tensor.shape().DebugString()));
    TensorShape output_shape(input_tensor.shape());
    output_shape.RemoveDim(0);
    OP_REQUIRES(c, element_shape.IsCompatibleWith(output_shape),
                errors::InvalidArgument(
                    "Specified a list with shape ", element_shape.DebugString(),
                    " from a tensor with shape ", output_shape.DebugString()));
    output_list.element_shape = element_shape;

    OP_REQUIRES(c, indices.NumElements() == input_tensor.shape().dim_size(0),
                errors::InvalidArgument(
                    "Invalid number of rows in input tensor. Expected: ",
                    indices.NumElements(),
                    " Actual: ", input_tensor.shape().dim_size(0)));

    // Validate indices and resize output_list.tensors to fit the highest index.
    {
      int highest_index = -1;
      for (int index = 0; index < indices.NumElements(); ++index) {
        const int i = indices.flat<int32>()(index);
        OP_REQUIRES(
            c, i >= 0,
            errors::InvalidArgument(
                "Indices in TensorListScatter must all be non-negative."));
        OP_REQUIRES(c, num_elements == -1 || i < num_elements,
                    errors::InvalidArgument(
                        "TensorListScatter: Trying to scatter at index ", i,
                        " in list with size ", num_elements));
        if (i > highest_index) {
          highest_index = i;
        }
      }
      output_list.tensors().resize(std::max(highest_index + 1, num_elements),
                                   Tensor(DT_INVALID));
    }

    OP_REQUIRES_OK(c,
                   Scatter<Device, T>(c, input_tensor, indices, &output_list));
    output_tensor->scalar<Variant>()() = std::move(output_list);
  }
};

template <typename Device>
Status TensorListBinaryAdd(OpKernelContext* c, const TensorList& a,
                           const TensorList& b, TensorList* out) {
  if (a.element_dtype != b.element_dtype) {
    return errors::InvalidArgument(
        "Trying to add two lists of tensors of different dtypes. One is ",
        DataTypeString(a.element_dtype), " and the other is ",
        DataTypeString(b.element_dtype));
  }
  out->element_dtype = a.element_dtype;
  if (!a.element_shape.IsCompatibleWith(b.element_shape)) {
    return errors::InvalidArgument(
        "Trying to add two lists of tensors with incompatible element shapes. "
        "One is ",
        a.element_shape.DebugString(), " and the other is ",
        b.element_shape.DebugString());
  }

  TF_RETURN_IF_ERROR(
      a.element_shape.MergeWith(b.element_shape, &out->element_shape));
  if (a.tensors().size() != b.tensors().size()) {
    return errors::InvalidArgument(
        "Trying to add two lists of tensors with different lengths. One is ",
        a.tensors().size(), " and the other is ", b.tensors().size());
  }
  out->tensors().reserve(a.tensors().size());
  for (int i = 0; i < a.tensors().size(); ++i) {
    const Tensor& a_tensor = a.tensors()[i];
    const Tensor& b_tensor = b.tensors()[i];
    Tensor out_tensor;
    TF_RETURN_IF_ERROR(
        BinaryAddTensors<Device>(c, a_tensor, b_tensor, &out_tensor));
    out->tensors().push_back(out_tensor);
  }
  return Status::OK();
}

template <typename Device>
Status TensorListZerosLike(OpKernelContext* c, const TensorList& x,
                           TensorList* y) {
  y->element_dtype = x.element_dtype;
  y->element_shape = x.element_shape;
  y->tensors().reserve(x.tensors().size());
  for (const Tensor& t : x.tensors()) {
    Tensor out_tensor;
    TF_RETURN_IF_ERROR(ZerosLikeTensor<Device>(c, t, &out_tensor));
    y->tensors().emplace_back(out_tensor);
  }
  return Status::OK();
}

template <typename Device, typename T>
class TensorListPushBackBatch : public OpKernel {
 public:
  explicit TensorListPushBackBatch(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_));
  }

  void Compute(OpKernelContext* c) override {
    const Tensor& input = c->input(1);
    OP_REQUIRES(c, element_dtype_ == input.dtype(),
                errors::InvalidArgument("Invalid data types; list elements ",
                                        DataTypeString(element_dtype_),
                                        " but tried to append ",
                                        DataTypeString(input.dtype())));
    OP_REQUIRES(c, TensorShapeUtils::IsVectorOrHigher(input.shape()),
                errors::InvalidArgument(
                    "Expected tensor to be at least a vector, but saw shape: ",
                    input.shape().DebugString()));

    const TensorShape& tls_shape = c->input(0).shape();

    // For purposes of input forwarding, we want the least restrictive
    // AllocatorAttributes possible.  If we need to allocate later,
    // we'll request the DT_VARIANT be allocated on host.
    AllocatorAttributes attr;

    std::unique_ptr<Tensor> tls_alias = c->forward_input(
        0 /*input_index*/, 0 /*output_index*/, DT_VARIANT, tls_shape,
        DEVICE_MEMORY /* input is always on DEVICE_MEMORY */, attr);

    bool ok_to_alias = tls_alias != nullptr;
    if (tls_alias && tls_alias->dtype() == DT_VARIANT &&
        tls_alias->NumElements() > 0) {
      auto alias_t = tls_alias->flat<Variant>();
      for (int i = 0; i < tls_alias->NumElements(); ++i) {
        TensorList* tl_i = alias_t(i).get<TensorList>();
        if (tl_i == nullptr || !tl_i->RefCountIsOne()) {
          ok_to_alias = false;
          break;
        }
      }
    }
    const Tensor& tls = ok_to_alias ? *tls_alias : c->input(0);

    OP_REQUIRES(c, tls.dtype() == DT_VARIANT,
                errors::InvalidArgument(
                    "Expected input_handles dtype to be Variant, but saw: ",
                    DataTypeString(tls.dtype())));
    OP_REQUIRES(c, TensorShapeUtils::IsVector(tls_shape),
                errors::InvalidArgument(
                    "Expected input_handles to be a vector, but saw shape: ",
                    tls_shape.DebugString()));
    const int64_t batch_size = tls.NumElements();
    OP_REQUIRES(c, input.dim_size(0) == batch_size,
                errors::InvalidArgument(
                    "Expected tensor.shape[0] == input_handles.size, but saw ",
                    input.dim_size(0), " vs. ", batch_size));
    auto tls_t = tls.vec<Variant>();

    TensorShape input_element_shape = input.shape();
    input_element_shape.RemoveDim(0);
    std::vector<const TensorList*> tl_batch;
    for (int64_t b = 0; b < batch_size; ++b) {
      const TensorList* l = tls_t(b).get<TensorList>();
      OP_REQUIRES(c, l != nullptr,
                  errors::InvalidArgument("Input handle at index ", b,
                                          " is not a list. Saw: '",
                                          tls_t(b).DebugString(), "'"));
      OP_REQUIRES(
          c, l->element_shape.IsCompatibleWith(input_element_shape),
          errors::InvalidArgument(
              "Tried to append a tensor with incompatible shape to a "
              "list at index ",
              b, ". Op element shape: ", input_element_shape.DebugString(),
              " list shape: ", l->element_shape.DebugString()));
      OP_REQUIRES(c, element_dtype_ == l->element_dtype,
                  errors::InvalidArgument(
                      "Invalid data type at index ", b, "; op elements ",
                      DataTypeString(element_dtype_), " but list elements ",
                      DataTypeString(l->element_dtype)));
      tl_batch.push_back(l);
    }

    Tensor* result;

    if (ok_to_alias) {
      result = tls_alias.get();
      c->set_output(0, *result);
    } else {
      // DT_VARIANT tensors always allocated on host.
      AllocatorAttributes attr;
      attr.set_on_host(true);
      OP_REQUIRES_OK(
          c, c->allocate_output(0, TensorShape{batch_size}, &result, attr));
    }

    if (batch_size == 0) {
      return;
    }

    auto input_t = input.flat_outer_dims<T, 2>();
    auto result_t = result->vec<Variant>();

    for (int64_t b = 0; b < batch_size; ++b) {
      if (!ok_to_alias) {
        result_t(b) = tl_batch[b]->Copy();
      }
      TensorList* output = result_t(b).get<TensorList>();
      DCHECK(output != nullptr);
      Tensor frame;
      OP_REQUIRES_OK(
          c, c->allocate_temp(element_dtype_, input_element_shape, &frame));
      if (input_element_shape.num_elements() > 0) {
        auto frame_t = frame.flat<T>();
        // TODO(penporn): Get this if out of the batch loop.
        if (IsPluggableDevice(c)) {
          // The chip method need Eigen Device, so need to use Tensor.Slice
          // instead of chip for pluggable device. The input should be reshaped
          // to 2-D and so can be sliced by batch dim.
          auto input_t_shape =
              TensorShape({input_t.dimension(0), input_t.dimension(1)});
          auto input_reshaped = Tensor();
          OP_REQUIRES(c, input_reshaped.CopyFrom(input, input_t_shape),
                      errors::Unknown("Unexpected shape error."));

          auto input_batch = input_reshaped.Slice(b, b + 1);
          CopyTensorPluggableDevice<T>(c, input_batch, frame);
        } else {
          frame_t.device(c->eigen_device<Device>()) =
              input_t.template chip<0>(b);
        }
      }
      output->tensors().push_back(std::move(frame));
    }
  }

 private:
  DataType element_dtype_;
};

}  // namespace tensorflow

#undef PLUGGABLE_DEVICE_SUPPORTED
#endif  // TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_


text:
namespace TSF.UmlToolingFramework.UML.Classes.Kernel {
	public interface  PackageableElement : NamedElement
	{
		Package owningPackage {get;set;}
	}
}

redpajama_set_name: RedPajamaGithub


text:
@interface MainTabBar()

@property (nonatomic, weak) UIButton *publishButton;

@end

@implementation MainTabBar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 设置tabbar的背景图片
        [self setBackgroundImage:[UIImage imageNamed:@"tabbar-light"]];

        // 添加发布按钮
        UIButton *publishButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [publishButton setBackgroundImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal];
        [publishButton setBackgroundImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted];
        [publishButton addTarget:self action:@selector(publishClick) forControlEvents:UIControlEventTouchUpInside];
        publishButton.size = publishButton.currentBackgroundImage.size;

        [self addSubview:publishButton];
        self.publishButton = publishButton;

    }
    return self;
}
- (void)publishClick
{

    PublishViewController *publishVC = [[PublishViewController alloc] init];
    [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:publishVC animated:NO completion:nil];
}
- (void)layoutSubviews
{
    [super layoutSubviews];

    static BOOL added = NO;

    CGFloat width = self.width;
    CGFloat height = self.height;

    //设置发布按钮的frame
    self.publishButton.center = CGPointMake(width * 0.5, height * 0.5);
    //设置其他UITabBarButton的frame
    CGFloat buttonY = 0;
    CGFloat buttonW = width / 5;
    CGFloat buttonH = height;
    NSInteger index = 0;
    for (UIControl *button in self.subviews) {
        if (![button isKindOfClass:[UIControl class]] || button == self.publishButton) {
            continue;
        }
        CGFloat buttonX = buttonW *((index > 1) ? (index + 1):index);
        button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH);
        //索引++
        index++;
        if (added == NO) {
            [button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
        }

    }
    added = YES;

}
- (void)buttonClick
{

}
@end


text:
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']

/*
Formats the given number using `Number#toLocaleString`.
- If locale is a string, the value is expected to be a locale-key (for example: `de`).
- If locale is true, the system default locale is used for translation.
- If no value for locale is specified, the number is returned unmodified.
*/
const toLocaleString = (number: number, locale: any) => {
  let result: any = number
  if (typeof locale === 'string') {
    result = number.toLocaleString(locale)
  } else if (locale === true) {
    result = number.toLocaleString()
  }

  return result
}

export default function prettyBytes(number: number, options?: any): string {
  if (!Number.isFinite(number)) {
    throw new TypeError(
      `Expected a finite number, got ${typeof number}: ${number}`
    )
  }

  options = Object.assign({}, options)

  if (options.signed && number === 0) {
    return ' 0 B'
  }

  const isNegative = number < 0
  const prefix = isNegative ? '-' : options.signed ? '+' : ''

  if (isNegative) {
    number = -number
  }

  if (number < 1) {
    const numberString = toLocaleString(number, options.locale)
    return prefix + numberString + ' B'
  }

  const exponent = Math.min(
    Math.floor(Math.log10(number) / 3),
    UNITS.length - 1
  )

  number = Number((number / Math.pow(1000, exponent)).toPrecision(3))
  const numberString = toLocaleString(number, options.locale)

  const unit = UNITS[exponent]

  return prefix + numberString + ' ' + unit
}


text:
SOMotionDetector
================

Simple library to detect motion for iOS by  arturdev .

Based on location updates and acceleration.

###Requierments
iOS > 6.0

Compatible with iOS 9

Works on all iOS devices (i.e. not need M7 chip)

This demo project also demonstrates how to use this library to relaunch the app from killed state.

USAGE
=====
Copy SOMotionDetector folder to your project.

Link CoreMotion.framework, CoreLocation.framework.

Import "SOMotionDetector.h" file and set SOMotionDetector's callbacks

```ObjC
#import "SOMotionDetector.h

//...

[SOMotionDetector sharedInstance].motionTypeChangedBlock = ^(SOMotionType motionType) {
    //...
};

[SOMotionDetector sharedInstance].locationChangedBlock = ^(CLLocation *location) {
    //...
};

[SOMotionDetector sharedInstance].accelerationChangedBlock = ^(CMAcceleration acceleration) {
    //...
};
```

If you need to know when location updates were automatically paused due to your app running in the background...

```ObjC
[SOMotionDetector sharedInstance].locationWasPausedBlock = ^(BOOL changed) {
    //...
};
```

###NOTE!
To Support iOS > 8.0 you must add in your info.plist file one of the following keys:

`NSLocationAlwaysUsageDescription`
 `NSLocationWhenInUseUsageDescription`

To enable background location updates in iOS > 9.0 you must set `allowsBackgroundLocationUpdates` to `YES`

```ObjC
    [SOLocationManager sharedInstance].allowsBackgroundLocationUpdates = YES;
```

You are done!

Now to start motion detection just call
```ObjC
[[SOMotionDetector sharedInstance] startDetection];
```

To stop detection call
```ObjC
[[SOMotionDetector sharedInstance] stopDetection];
```

To start step counter call
```ObjC
    [[SOStepDetector sharedInstance] startDetectionWithUpdateBlock:^(NSError *error) {
        //...
    }];
```
###Detecting motion types
```ObjC
typedef enum
{
  MotionTypeNotMoving = 1,
  MotionTypeWalking,
  MotionTypeRunning,
  MotionTypeAutomotive
} SOMotionType;
```

CUSTOMIZATION
=============
```ObjC

/**
 * Set this parameter to YES if you want to use M7 chip to detect more exact motion type. By default is No.
 * Set this parameter before calling startDetection method.
 * Available only on devices that have M7 chip. At this time only the iPhone 5S, the iPad Air and iPad mini with retina display have the M7 coprocessor.
 */
@property (nonatomic) BOOL useM7IfAvailable;

/**
 *@param speed  The minimum speed value less than which will be considered as not moving state
 */
- (void)setMinimumSpeed:(CGFloat)speed;

/**
 *@param speed  The maximum speed value more than which will be considered as running state
 */
- (void)setMaximumWalkingSpeed:(CGFloat)speed;

/**
 *@param speed  The maximum speed value more than which will be considered as automotive state
 */
- (void)setMaximumRunningSpeed:(CGFloat)speed;

/**
 *@param acceleration  The minimum acceleration value less than which will be considered as non shaking state
 */
- (void)setMinimumRunningAcceleration:(CGFloat)acceleration;

```

### Installation with CocoaPods

[CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries installation in your projects.

#### Podfile

```ruby
pod "SOMotionDetector"
```

LICENSE

SOMotionDetector is under MIT License (see LICENSE file)


text:
//Apache2, 2016-present, WinterDev
using System;
using System.IO;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//from https://www.microsoft.com/typography/developers/opentype/detail.htm
//GDEF Table
//As discussed in Part One,
//the most important tables for glyph processing are GSUB and GPOS,
//but both these tables make use of data in the Glyph Definition table.
//The GDEF table contains three kinds of information in subtables:
//1. glyph class definitions that classify different types of glyphs in a font;
//2. attachment point lists that identify glyph positioning attachments for each glyph;
//and 3. ligature caret lists that provide information for caret positioning and text selection involving ligatures.

//The Glyph Class Definition subtable identifies
//four glyph classes:
//1. simple glyphs,
//2. ligature glyphs (glyphs representing two or more glyph components),
//3. combining mark glyphs (glyphs that combine with other classes),
//and 4. glyph components (glyphs that represent individual parts of ligature glyphs).

//These classes are used by both GSUB and GPOS to differentiate glyphs in a string; for example,
//to distinguish between a base vowel (simple glyph)
//and the accent (combining mark glyph) that a GPOS feature will position above it.

//The Attachment Point List
//identifies all the glyph attachment points defined in the GPOS table.
//Clients that access this information in the GDEF table can cache attachment coordinates with the rasterized glyph bitmaps,
//and avoid having to recalculate the attachment points each time they display a glyph.
//Without this table,
//GPOS features could still be enabled,
//but processing speed would be slower because the client would need to decode the GPOS lookups
//that define the attachment points and compile its own list.

//The Ligature Caret List
//defines the positions for the caret to occupy in ligatures.
//This information, which can be fine tuned for particular bitmap sizes,
//makes it possible for the caret to step across the component characters of a ligature, and for the user to select text including parts of ligatures.
//In the example on the left, below, the caret is positioned between two components of a ligature; on the right, text is selected from within a ligature.
//

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//https://www.microsoft.com/typography/otspec/GDEF.htm
//GDEF — Glyph Definition Table

//The Glyph Definition (GDEF) table contains six types of information in six independent tables:

//    The GlyphClassDef table classifies the different types of glyphs in the font.
//    The AttachmentList table identifies all attachment points on the glyphs, which streamlines data access and bitmap caching.
//    The LigatureCaretList table contains positioning data for ligature carets, which the text-processing client uses on screen to select and highlight the individual components of a ligature glyph.
//    The MarkAttachClassDef table classifies mark glyphs, to help group together marks that are positioned similarly.
//    The MarkGlyphSetsTable allows the enumeration of an arbitrary number of glyph sets that can be used as an extension of the mark attachment class definition to allow lookups to filter mark glyphs by arbitrary sets of marks.
//    The ItemVariationStore table is used in variable fonts to contain variation data used for adjustment of values in the GDEF, GPOS or JSTF tables.

//The GSUB and GPOS tables may reference certain GDEF table information used for processing of lookup tables. See, for example, the LookupFlag bit enumeration in "OpenType Layout Common Table Formats".

//In variable fonts, the GDEF, GPOS and JSTF tables may all reference variation data within the ItemVariationStore table contained within the GDEF table. See below for further discussion of variable fonts and the ItemVariationStore table.
///////////////////////////////////////////////////////////////////////////////

namespace Typography.OpenFont.Tables
{

    class GDEF : TableEntry
    {
        long tableStartAt;

        public override string Name
        {
            get { return "GDEF"; }
        }

        protected override void ReadContentFrom(BinaryReader reader)
        {
            tableStartAt = reader.BaseStream.Position;
            //-----------------------------------------
            //GDEF Header, Version 1.0
            //Type 	    Name 	            Description
            //uint16 	MajorVersion 	    Major version of the GDEF table, = 1
            //uint16 	MinorVersion 	    Minor version of the GDEF table, = 0
            //Offset16 	GlyphClassDef 	    Offset to class definition table for glyph type, from beginning of GDEF header (may be NULL)
            //Offset16 	AttachList  	    Offset to list of glyphs with attachment points, from beginning of GDEF header (may be NULL)
            //Offset16 	LigCaretList 	    Offset to list of positioning points for ligature carets, from beginning of GDEF header (may be NULL)
            //Offset16 	MarkAttachClassDef 	Offset to class definition table for mark attachment type, from beginning of GDEF header (may be NULL)
            //
            //GDEF Header, Version 1.2
            //Type 	Name 	Description
            //uint16 	MajorVersion 	    Major version of the GDEF table, = 1
            //uint16 	MinorVersion 	    Minor version of the GDEF table, = 2
            //Offset16 	GlyphClassDef 	    Offset to class definition table for glyph type, from beginning of GDEF header (may be NULL)
            //Offset16 	AttachList 	        Offset to list of glyphs with attachment points, from beginning of GDEF header (may be NULL)
            //Offset16 	LigCaretList 	    Offset to list of positioning points for ligature carets, from beginning of GDEF header (may be NULL)
            //Offset16 	MarkAttachClassDef 	Offset to class definition table for mark attachment type, from beginning of GDEF header (may be NULL)
            //Offset16 	MarkGlyphSetsDef 	Offset to the table of mark set definitions, from beginning of GDEF header (may be NULL)
            //
            //GDEF Header, Version 1.3
            //Type 	Name 	Description
            //uint16 	MajorVersion 	    Major version of the GDEF table, = 1
            //uint16 	MinorVersion 	    Minor version of the GDEF table, = 3
            //Offset16 	GlyphClassDef 	    Offset to class definition table for glyph type, from beginning of GDEF header (may be NULL)
            //Offset16 	AttachList  	    Offset to list of glyphs with attachment points, from beginning of GDEF header (may be NULL)
            //Offset16 	LigCaretList 	    Offset to list of positioning points for ligature carets, from beginning of GDEF header (may be NULL)
            //Offset16 	MarkAttachClassDef 	Offset to class definition table for mark attachment type, from beginning of GDEF header (may be NULL)
            //Offset16 	MarkGlyphSetsDef 	Offset to the table of mark set definitions, from beginning of GDEF header (may be NULL)
            //Offset32 	ItemVarStore 	    Offset to the Item Variation Store table, from beginning of GDEF header (may be NULL)

            //common to 1.0, 1.2, 1.3...
            this.MajorVersion = reader.ReadUInt16();
            this.MinorVersion = reader.ReadUInt16();
            //
            ushort glyphClassDefOffset = reader.ReadUInt16();
            ushort attachListOffset = reader.ReadUInt16();
            ushort ligCaretListOffset = reader.ReadUInt16();
            ushort markAttachClassDefOffset = reader.ReadUInt16();
            ushort markGlyphSetsDefOffset = 0;
            uint itemVarStoreOffset = 0;
            //
            switch (MinorVersion)
            {
                default:
                    Utils.WarnUnimplemented("GDEF Minor Version {0}", MinorVersion);
                    return;
                case 0:
                    break;
                case 2:
                    markGlyphSetsDefOffset = reader.ReadUInt16();
                    break;
                case 3:
                    markGlyphSetsDefOffset = reader.ReadUInt16();
                    itemVarStoreOffset = reader.ReadUInt32();
                    break;
            }
            //---------------

            this.GlyphClassDef = (glyphClassDefOffset == 0) ? null : ClassDefTable.CreateFrom(reader, tableStartAt + glyphClassDefOffset);
            this.AttachmentListTable = (attachListOffset == 0) ? null : AttachmentListTable.CreateFrom(reader, tableStartAt + attachListOffset);
            this.LigCaretList = (ligCaretListOffset == 0) ? null : LigCaretList.CreateFrom(reader, tableStartAt + ligCaretListOffset);

            //A Mark Attachment Class Definition Table defines the class to which a mark glyph may belong.
            //This table uses the same format as the Class Definition table (for details, see the chapter, Common Table Formats ).

#if DEBUG
            if (markAttachClassDefOffset == 2)
            {
                //temp debug invalid font
                this.MarkAttachmentClassDef = (markAttachClassDefOffset == 0) ? null : ClassDefTable.CreateFrom(reader, reader.BaseStream.Position);
            }
            else
            {
                this.MarkAttachmentClassDef = (markAttachClassDefOffset == 0) ? null : ClassDefTable.CreateFrom(reader, tableStartAt + markAttachClassDefOffset);
            }
#else
            this.MarkAttachmentClassDef = (markAttachClassDefOffset == 0) ? null : ClassDefTable.CreateFrom(reader, tableStartAt + markAttachClassDefOffset);
#endif

            this.MarkGlyphSetsTable = (markGlyphSetsDefOffset == 0) ? null : MarkGlyphSetsTable.CreateFrom(reader, tableStartAt + markGlyphSetsDefOffset);

            if (itemVarStoreOffset != 0)
            {
                //not supported
                Utils.WarnUnimplemented("GDEF ItemVarStore");
                reader.BaseStream.Seek(this.Header.Offset + itemVarStoreOffset, SeekOrigin.Begin);
            }
        }
        public int MajorVersion { get; private set; }
        public int MinorVersion { get; private set; }
        public ClassDefTable GlyphClassDef { get; private set; }
        public AttachmentListTable AttachmentListTable { get; private set; }
        public LigCaretList LigCaretList { get; private set; }
        public ClassDefTable MarkAttachmentClassDef { get; private set; }
        public MarkGlyphSetsTable MarkGlyphSetsTable { get; private set; }

        //------------------------
        /// <summary>
        /// fill gdef to each glyphs
        /// </summary>
        /// <param name="inputGlyphs"></param>
        public void FillGlyphData(Glyph[] inputGlyphs)
        {
            //1.
            FillClassDefs(inputGlyphs);
            //2.
            FillAttachPoints(inputGlyphs);
            //3.
            FillLigatureCarets(inputGlyphs);
            //4.
            FillMarkAttachmentClassDefs(inputGlyphs);
            //5.
            FillMarkGlyphSets(inputGlyphs);
        }
        void FillClassDefs(Glyph[] inputGlyphs)
        {
            //1. glyph def
            ClassDefTable classDef = GlyphClassDef;
            if (classDef == null) return;
            //-----------------------------------------

            switch (classDef.Format)
            {
                default:
                    Utils.WarnUnimplemented("GDEF GlyphClassDef Format {0}", classDef.Format);
                    break;
                case 1:
                    {
                        ushort startGlyph = classDef.startGlyph;
                        ushort[] classValues = classDef.classValueArray;
                        int len = classValues.Length;
                        int gIndex = startGlyph;
                        for (int i = 0; i < len; ++i)
                        {
                            inputGlyphs[gIndex].GlyphClass = (GlyphClassKind)classValues[i];
                            gIndex++;
                        }

                    }
                    break;
                case 2:
                    {
                        ClassDefTable.ClassRangeRecord[] records = classDef.records;
                        int len = records.Length;
                        for (int n = 0; n < len; ++n)
                        {
                            ClassDefTable.ClassRangeRecord rec = records[n];
                            GlyphClassKind glyphKind = (GlyphClassKind)rec.classNo;
                            for (int i = rec.startGlyphId; i <= rec.endGlyphId; ++i)
                            {
                                inputGlyphs[i].GlyphClass = glyphKind;
                            }
                        }
                    }
                    break;
            }
        }
        void FillAttachPoints(Glyph[] inputGlyphs)
        {
            AttachmentListTable attachmentListTable = this.AttachmentListTable;
            if (attachmentListTable == null) { return; }
            //-----------------------------------------

            Utils.WarnUnimplemented("please implement GDEF.FillAttachPoints()");
        }
        void FillLigatureCarets(Glyph[] inputGlyphs)
        {
            //Console.WriteLine("please implement FillLigatureCarets()");
        }
        void FillMarkAttachmentClassDefs(Glyph[] inputGlyphs)
        {
            //Mark Attachment Class Definition Table
            //A Mark Class Definition Table is used to assign mark glyphs into different classes
            //that can be used in lookup tables within the GSUB or GPOS table to control how mark glyphs within a glyph sequence are treated by lookups.
            //For more information on the use of mark attachment classes,
            //see the description of lookup flags in the "Lookup Table" section of the chapter, OpenType Layout Common Table Formats.
            ClassDefTable markAttachmentClassDef = this.MarkAttachmentClassDef;
            if (markAttachmentClassDef == null) return;
            //-----------------------------------------

            switch (markAttachmentClassDef.Format)
            {
                default:
                    Utils.WarnUnimplemented("GDEF MarkAttachmentClassDef Table Format {0}", markAttachmentClassDef.Format);
                    break;
                case 1:
                    {
                        ushort startGlyph = markAttachmentClassDef.startGlyph;
                        ushort[] classValues = markAttachmentClassDef.classValueArray;

                        int len = classValues.Length;
                        int gIndex = startGlyph;
                        for (int i = 0; i < len; ++i)
                        {
#if DEBUG
                            Glyph dbugTestGlyph = inputGlyphs[gIndex];
#endif
                            inputGlyphs[gIndex].MarkClassDef = classValues[i];
                            gIndex++;
                        }

                    }
                    break;
                case 2:
                    {
                        ClassDefTable.ClassRangeRecord[] records = markAttachmentClassDef.records;
                        int len = records.Length;
                        for (int n = 0; n < len; ++n)
                        {
                            ClassDefTable.ClassRangeRecord rec = records[n];
                            for (int i = rec.startGlyphId; i <= rec.endGlyphId; ++i)
                            {
#if DEBUG
                                Glyph dbugTestGlyph = inputGlyphs[i];
#endif
                                inputGlyphs[i].MarkClassDef = rec.classNo;
                            }
                        }
                    }
                    break;
            }
        }
        void FillMarkGlyphSets(Glyph[] inputGlyphs)
        {
            //Mark Glyph Sets Table
            //A Mark Glyph Sets table is used to define sets of mark glyphs that can be used in lookup tables within the GSUB or GPOS table to control
            //how mark glyphs within a glyph sequence are treated by lookups. For more information on the use of mark glyph sets,
            //see the description of lookup flags in the "Lookup Table" section of the chapter, OpenType Layout Common Table Formats.
            MarkGlyphSetsTable markGlyphSets = this.MarkGlyphSetsTable;
            if (markGlyphSets == null) return;
            //-----------------------------------------

            Utils.WarnUnimplemented("please implement GDEF.FillMarkGlyphSets()");
        }
    }
}


text:
import {BaseIfc} from "./BaseIfc"
import {IfcLabel} from "./IfcLabel.g"
import {IfcPresentationItem} from "./IfcPresentationItem.g"

/**
 * http://www.buildingsmart-tech.org/ifc/IFC4/final/html/link/ifcpredefineditem.htm
 */
export abstract class IfcPreDefinedItem extends IfcPresentationItem {
	Name : IfcLabel

    constructor(name : IfcLabel) {
        super()
		this.Name = name

    }
}


text:
from __future__ import print_function

import sys
import numpy as np

import cv2
from time import time
import os
import dlib

INNER_EYES_AND_BOTTOM_LIP = [39, 42, 57, 58]
OUTER_EYES_AND_NOSE = [36, 45, 33, 58]

TEMPLATE = np.float32([
    (0.0792396913815, 0.339223741112), (0.0829219487236, 0.456955367943),
    (0.0967927109165, 0.575648016728), (0.122141515615, 0.691921601066),
    (0.168687863544, 0.800341263616), (0.239789390707, 0.895732504778),
    (0.325662452515, 0.977068762493), (0.422318282013, 1.04329000149),
    (0.531777802068, 1.06080371126), (0.641296298053, 1.03981924107),
    (0.738105872266, 0.972268833998), (0.824444363295, 0.889624082279),
    (0.894792677532, 0.792494155836), (0.939395486253, 0.681546643421),
    (0.96111933829, 0.562238253072), (0.970579841181, 0.441758925744),
    (0.971193274221, 0.322118743967), (0.163846223133, 0.249151738053),
    (0.21780354657, 0.204255863861), (0.291299351124, 0.192367318323),
    (0.367460241458, 0.203582210627), (0.4392945113, 0.233135599851),
    (0.586445962425, 0.228141644834), (0.660152671635, 0.195923841854),
    (0.737466449096, 0.182360984545), (0.813236546239, 0.192828009114),
    (0.8707571886, 0.235293377042), (0.51534533827, 0.31863546193),
    (0.516221448289, 0.396200446263), (0.517118861835, 0.473797687758),
    (0.51816430343, 0.553157797772), (0.433701156035, 0.604054457668),
    (0.475501237769, 0.62076344024), (0.520712933176, 0.634268222208),
    (0.565874114041, 0.618796581487), (0.607054002672, 0.60157671656),
    (0.252418718401, 0.331052263829), (0.298663015648, 0.302646354002),
    (0.355749724218, 0.303020650651), (0.403718978315, 0.33867711083),
    (0.352507175597, 0.349987615384), (0.296791759886, 0.350478978225),
    (0.631326076346, 0.334136672344), (0.679073381078, 0.29645404267),
    (0.73597236153, 0.294721285802), (0.782865376271, 0.321305281656),
    (0.740312274764, 0.341849376713), (0.68499850091, 0.343734332172),
    (0.353167761422, 0.746189164237), (0.414587777921, 0.719053835073),
    (0.477677654595, 0.706835892494), (0.522732900812, 0.717092275768),
    (0.569832064287, 0.705414478982), (0.635195811927, 0.71565572516),
    (0.69951672331, 0.739419187253), (0.639447159575, 0.805236879972),
    (0.576410514055, 0.835436670169), (0.525398405766, 0.841706377792),
    (0.47641545769, 0.837505914975), (0.41379548902, 0.810045601727),
    (0.380084785646, 0.749979603086), (0.477955996282, 0.74513234612),
    (0.523389793327, 0.748924302636), (0.571057789237, 0.74332894691),
    (0.672409137852, 0.744177032192), (0.572539621444, 0.776609286626),
    (0.5240106503, 0.783370783245), (0.477561227414, 0.778476346951)])

TPL_MIN, TPL_MAX = np.min(TEMPLATE, axis=0), np.max(TEMPLATE, axis=0)
MINMAX_TEMPLATE = (TEMPLATE - TPL_MIN) / (TPL_MAX - TPL_MIN)

def parse_args():
    print(' '.join(sys.argv))
    import argparse
    parser = argparse.ArgumentParser(
        epilog="Output file format: frame_id\\tface_id\\tbbox_left:bbox_top:bbox_right:bbox_bottom\\tlandmark1_x:landmark1_y\\tlandmark2_x:landmark2_y\\t...landmarkn_x:landmarkn_y")

    parser.add_argument('--input-video',
                        default='./dev_1.mp4',
                        help='Input video.')
    parser.add_argument('--landmark-model', required=True,
                        help='Path to dlib shape predictor model shape_predictor_68_face_landmarks.dat.')
    parser.add_argument('--downscale-factor',
                        default=4,
                        type=float,
                        help='Downslace factor of the image.')
    parser.add_argument('--align-version',
                        default=1,
                        type=int,
                        help='Version of alignment.')
    parser.add_argument('--crop-resolution',
                        default=128,
                        type=int,
                        help='Resolution of cropped faces.')
    parser.add_argument('--crop-scale',
                        default=1,
                        type=float,
                        help='Scale factor of the facial crop box.')
    parser.add_argument('-o', '--out-dir',
                        required=True,
                        help='Output directory.')
    parser.add_argument('--landmark-file',
                        help='Where to write detected faces, landmarks, ... If no specified out-dir/landmarks.txt')
    parser.add_argument('--skip-frames',
                        default=0, type=int,
                        help='How many frames to skip between two processed frames.')
    parser.add_argument('-v', '--verbose',
                        action='store_true')
    parser.add_argument('--detector_path', required=True,
                        help='Path to the mtcnn networks.')

    args = parser.parse_args()

    if not args.landmark_file:
        args.landmark_file = os.path.join(args.out_dir, "landmarks.csv")

    return args

def loadBBoxFile(fileName):
    inputFileTxt = open(fileName, "r")
    lines = inputFileTxt.readlines()
    lastFrameId = -1
    BBoxList = []
    for i in range(len(lines)):
        line = lines[i].rstrip().split('\t')
        dRect = dlib.rectangle(
            left=int(line[2]), top=int(line[3]),
            right=int(line[4]), bottom=int(line[5]))
        frameId = int(line[0])
        if lastFrameId != frameId:
            dRectList = dlib.rectangles()
            BBoxList.append(dRectList)
        dlib.rectangles.append(dRectList, dRect)
        lastFrameId = frameId
    print("Loaded {} bounding boxes for {} frames.".format(len(lines),
          len(BBoxList)))
    return BBoxList

def loadLandmarkFile(fileName):
    inputFileTxt = open(fileName, "r")
    lines = inputFileTxt.readlines()
    lastFrameId = -1
    landmarksList = []
    for i in range(len(lines)):
        line = lines[i].rstrip().split('\t')

        rectStr = line[2].split(':')
        rect = dlib.rectangle(
            left=int(rectStr[0]), top=int(rectStr[1]),
            right=int(rectStr[2]), bottom=int(rectStr[3]))

        parts = []
        for j in range(len(line) - 5):
            pointStr = line[j + 3].split(':')
            parts.append(dlib.point(x=int(pointStr[0]), y=int(pointStr[1])))

        shape = dlib.full_object_detection(rect, parts)
        frameId = int(line[0])
        if lastFrameId != frameId:
            shapeList = []
            landmarksList.append(shapeList)
        shapeList.append(shape)
        lastFrameId = frameId

    print("Loaded landmarks for {} faces in {} frames.".format(len(lines),
          len(landmarksList)))
    return landmarksList

def saveFaces(fileLandmarks, frameId, k, shape):
    rectStr = ":".join((
        str(shape.rect.left()), str(shape.rect.top()),
        str(shape.rect.right()), str(shape.rect.bottom())))
    partsStr = '\t'.join(
        [':'.join((str(i.x), str(i.y))) for i in shape.parts()])
    fileLandmarks.write(
        "{}\t{}\t{}\t{}\n".format(frameId, k, rectStr, partsStr))

def getRigidTransform(p1, p2):
    p2 = p2.reshape(p2.size)
    lines = []
    for p in p1:
        lines.append(np.asarray([p[0], p[1], 1, 0]))
        lines.append(np.asarray([p[1], -p[0], 0, 1]))
    lines = np.vstack(lines)
    m, residual, rank, s = np.linalg.lstsq(lines, p2)
    H = np.identity(3)
    H[0, 0] = m[0]
    H[0, 1] = m[1]
    H[0, 2] = m[2]
    H[1, 0] = -m[1]
    H[1, 1] = m[0]
    H[1, 2] = m[3]
    return H

# not used at the moment
def alignFace_v1(shape, frame, landmarkIndices=OUTER_EYES_AND_NOSE, imgDim=260, cropScale=1.0):
    landmarks= list(map(lambda p: (p.x, p.y), shape.parts()))

    npLandmarks = np.float32(landmarks)
    npLandmarkIndices = np.array(landmarkIndices)

    faceResolution = imgDim * 1/cropScale
    faceBorder = faceResolution * (cropScale - 1) / 2

    P1 = npLandmarks
    P1 = P1.reshape((1, -1, 2))
    P1 = P1
    P2 = faceBorder + faceResolution * MINMAX_TEMPLATE
    P2 = P2.reshape((1, -1, 2))
    H = cv2.estimateRigidTransform( P1.astype(np.float32), P2.astype(np.float32), fullAffine=False)

    H2 = getRigidTransform(npLandmarks, faceBorder + faceResolution * MINMAX_TEMPLATE)

    thumbnail = cv2.warpAffine(frame, H2[0:2,:], (imgDim, imgDim), borderMode=cv2.BORDER_REPLICATE)
    return thumbnail

class faceAligner(object):
    '''
    Is able to compute precise and axis-aligned face bounding boxes,
    crop faces, draw BB, ...
    '''
    def __init__(self, faceResolution, cropResolution, landmarkIndices=np.array(range(60))):
        self.landmarkIndices = landmarkIndices
        self.faceResolution = faceResolution
        self.faceBorder = (cropResolution - faceResolution) / 2
        self.cropResolution = tuple(cropResolution.tolist())
        self.bBox = dlib.rectangle(
            left=self.faceBorder[1], top=self.faceBorder[0],
            right=self.faceBorder[1] + self.faceResolution[1],
            bottom=self.faceBorder[0] + self.faceResolution[0])
        self.bBoxMat = np.array([
            [self.faceBorder[1], self.faceBorder[0], 1],
            [self.faceBorder[1] + self.faceResolution[1], self.faceBorder[0], 1],
            [self.faceBorder[1] + self.faceResolution[1], self.faceBorder[0] + self.faceResolution[0], 1],
            [self.faceBorder[1], self.faceBorder[0] + self.faceResolution[0], 1],
            ]).T

    def getTranformation(self, shape):
        ''' Computes rigid body face trasformation '''
        if not isinstance(shape, list):
            landmarks = [(p.x, p.y) for p in shape.parts()]
        else:
            landmarks = shape
        landmarks = np.float32(landmarks)
        H = getRigidTransform(
            landmarks[self.landmarkIndices],
            self.faceBorder + self.faceResolution * MINMAX_TEMPLATE[self.landmarkIndices])
        return H

    def transform(self, frame, H):
        ''' Crop face '''
        return cv2.warpAffine(
            frame, H[0:2, :], self.cropResolution,
            borderMode=cv2.BORDER_REPLICATE)

    def getCropBBox(self):
        ''' Return tight face bounding box in the face crop. '''
        return self.bBox

    def getPreciseBBox(self, H):
        ''' Return tight face bounding box in the face crop. '''
        bbox = np.linalg.inv(H).dot(self.bBoxMat)
        bbox = bbox[0:2, :] / bbox[2, :]
        return bbox

    def getSimpleBBox(self, H):
        bbox = self.getPreciseBBox(H)
        tl = bbox[:, 0].reshape(-1)
        tr = bbox[:, 1].reshape(-1)
        br = bbox[:, 2].reshape(-1)
        center = (tl + br) / 2
        radius = np.linalg.norm((tl - tr) / 2) * 1.1
        rect = dlib.rectangle(
            left=int(center[0] - radius), top=int(center[1] - radius),
            right=int(center[0] + radius), bottom=int(center[1] + radius))
        return rect

    def drawPreciseBBox(self, frame, H, color=(0, 255, 0), thickness=1):
        bbox = self.getPreciseBBox(H).astype(np.int32)
        for p1 in range(4):
            p2 = (p1 + 1) % 4
            cv2.line(
                frame, pt1=(bbox[0, p1], bbox[1, p1]),
                pt2=(bbox[0, p2], bbox[1, p2]),
                color=color, thickness=thickness)

# not used at the moment
class faceTracker(object):
    instanceCounter = 0
    def __init__(self, faceResolution, cropResolution, facePredictor, detector, trackingIterations=1):
        self.aligner = faceAligner(faceResolution, cropResolution)
        self.trackingIterations = trackingIterations
        self.facePredictor = facePredictor
        self.frameBBox = None
        self.ID = faceTracker.instanceCounter
        self.detector = detector
        faceTracker.instanceCounter += 1

    def localizeFeatures(self, frame, bbox):
        return self.facePredictor(frame, bbox)

    def start(self, frame, bbox):
        shape = self.localizeFeatures(frame, bbox)
        self.H = self.aligner.getTranformation(shape)
        self.nextFrame( frame)
        return self

    def nextFrame(self, frame):
        for i in range(self.trackingIterations):
            crop = self.aligner.transform(frame, self.H)
            shape = self.localizeFeatures(crop, self.aligner.getCropBBox())
            H = self.aligner.getTranformation(shape)
            self.H = H.dot(self.H)
        self.frameBBox = self.aligner.getPreciseBBox(self.H)

    def getCrop(self, frame):
        return self.aligner.transform(frame, self.H)

class faceTrackerOrig(object):
    instanceCounter = 0
    def __init__(self, faceResolution, cropResolution, facePredictor, trackingIterations=1):
        self.trackingIterations = trackingIterations
        self.faceAligner = faceAligner(faceResolution, cropResolution)
        self.facePredictor = facePredictor
        self.frameBBox = None
        self.ID = faceTracker.instanceCounter
        self.shape = None
        faceTracker.instanceCounter += 1

    def localizeFeatures(self, frame, bbox):
        return self.facePredictor(frame, bbox)

    def start(self, frame, bbox):
        self.shape = self.localizeFeatures(frame, bbox)
        self.H = self.faceAligner.getTranformation(self.shape)
        self.frameBBox = self.faceAligner.getPreciseBBox(self.H)
        return self

    def nextFrame(self, frame):
        for i in range(self.trackingIterations):
            self.shape = self.localizeFeatures(frame, self.faceAligner.getSimpleBBox(self.H))
            self.H = self.faceAligner.getTranformation(self.shape)
        self.frameBBox = self.faceAligner.getPreciseBBox(self.H)

    def getCrop(self, frame):
        return self.faceAligner.transform(frame, self.H)

def bboxSize(bbox):
    tl = bbox[:, 0].reshape(-1)
    br = bbox[:, 2].reshape(-1)
    return np.linalg.norm((tl - br) / 2)

class faceDetector(object):
    def __init__(self, detector_downscale=1.0):
        self.detector = dlib.get_frontal_face_detector()
        self.detector_downscale = detector_downscale

    def __call__(self, frame):
        if self.detector_downscale != 1.0:
            frame = cv2.resize(
                frame, (0, 0), fx=1. / self.detector_downscale,
                fy=1. / self.detector_downscale, interpolation=cv2.INTER_AREA)

        # The second paprameter is upscale factor
        dets = self.detector(frame, 1)
        for k, bbox in enumerate(dets):
            dets[k] = dlib.rectangle(
                left=int(bbox.left() * self.detector_downscale + 0.5),
                top=int(bbox.top() * self.detector_downscale + 0.5),
                right=int(bbox.right() * self.detector_downscale + 0.5),
                bottom=int(bbox.bottom() * self.detector_downscale + 0.5))
        return dets

class multipleFaceTracker(object):
    def __init__(self, landmark_model, detector, verbose=True):
        self.detector = detector
        self.facePredictor = dlib.shape_predictor(landmark_model)
        self.verbose = verbose
        if self.verbose:
            self.win = dlib.image_window()
        self.faceAligner = faceAligner(
            faceResolution=np.array((64, 64)),
            cropResolution=np.array((96, 96)))

        self.trackedFaces = []

        self.trackedFaceResolution = np.array((128, 128))
        self.trackedCropResolution = np.array((192, 192))
        self.overlapThreshold = 0.35
        self.frameID = 0
        self.detectStep = 1
        self.faceID = 0

    def getFacePositions(self):
        trackedCenters = []
        trackedRadiuses = []
        if self.trackedFaces:
            for face in self.trackedFaces:
                tl = face.frameBBox[:, 0].reshape(-1)
                br = face.frameBBox[:, 2].reshape(-1)
                trackedCenters.append((tl + br) / 2)
                trackedRadiuses.append(np.linalg.norm((tl - br) / 2))
            trackedCenters = np.vstack(trackedCenters)
            trackedRadiuses = np.array(trackedRadiuses)
        return trackedCenters, trackedRadiuses

    def computeOverlapMatrix(self, detections):
        trackedCenters, trackedRadiuses = self.getFacePositions()
        overlapMatrix = np.zeros(
            (len(trackedCenters) + 1, len(detections) + 1))
        if len(trackedCenters) > 0:
            for num, bbox in enumerate(detections):
                tl = np.array([bbox.left(), bbox.top()])
                br = np.array([bbox.right(), bbox.bottom()])
                detCenter = (tl + br) / 2
                detRadius = np.linalg.norm((tl - br) / 2)
                distances = np.sqrt(
                    np.sum((detCenter - trackedCenters) ** 2, axis=1))
                r = np.minimum(trackedRadiuses, detRadius)
                R = np.maximum(trackedRadiuses, detRadius)
                overlaps = r / R * (1 - distances / (r + R))
                overlapMatrix[0:-1, num] = overlaps

        return overlapMatrix

    def terminateTracksAddDetections(self, frame, detections):

        # colums are for detections (dim2 indexes detections)
        # rows are for tracked faces (dim1 indexes faces)
        overlapMatrix = self.computeOverlapMatrix(detections)

        # remove and update existing tracks
        newTracks = []
        for trackOverlaps, trackedFace in zip(overlapMatrix, self.trackedFaces):
            closestID = np.argmax(trackOverlaps)
            if trackOverlaps[closestID] >= self.overlapThreshold:
                newTracks.append(trackedFace.start(frame, detections[closestID]))

        # add non-tracked detections
        for detectionOverlaps, detection in zip(overlapMatrix.T, detections):
            if detectionOverlaps.max() < self.overlapThreshold:
                faceTrack = faceTrackerOrig(
                    faceResolution=self.trackedFaceResolution,
                    cropResolution=self.trackedCropResolution,
                    facePredictor=self.facePredictor)
                newTracks.append(faceTrack.start(frame, detection))

        self.trackedFaces = newTracks

    def processFrame(self, frame):
        origFrame = frame
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        if self.frameID % self.detectStep == 0:
            dets, points = self.detector(frame)
            self.terminateTracksAddDetections(frame, dets)
        else:
            for face in self.trackedFaces:
                face.nextFrame(frame)

        self.frameID += 1

        if self.verbose:
            visFrame = origFrame.copy()
            for face in self.trackedFaces:
                face.faceAligner.drawPreciseBBox(
                    visFrame, face.H, color=(0, 255, 0), thickness=1)
            cv2.imshow('vis', visFrame)
            cv2.waitKey(1)

        return [(f.ID, f.shape) for f in self.trackedFaces]

def cropFace(frame, shape, align_version=1, cropSize=128, cropScale=1.5):
    if align_version == 1:
        crop = alignFace_v1(shape, frame, imgDim=cropSize, cropScale=cropScale)
    else:
        print(
            "Alignment number {} is not implemented.".format(align_version),
            file=sys.stderr)
        exit(-1)

    crop = cv2.cvtColor(crop, cv2.COLOR_BGR2RGB)
    return crop

from CNNdetector import mtcnnFaceDetector

####################################################################
# main
####################################################################
def main():

    frameId = 0
    args = parse_args()

    cap = cv2.VideoCapture(args.input_video)
    resolution = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
                  int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    pixels = resolution[0] * resolution[1]
    targetPixels = 80000
    if not args.downscale_factor:
        args.downscale_factor = max((pixels / targetPixels) ** 0.5, 1)
    print('INFO downscale_factor {}'.format(args.downscale_factor))

    detector = mtcnnFaceDetector(args.detector_path)
    tracker = multipleFaceTracker(
        landmark_model=args.landmark_model,
        detector=detector, verbose=args.verbose)

    # used to make output face crops
    aligner = faceAligner(
        faceResolution=np.array((
            int(args.crop_resolution / args.crop_scale),
            int(args.crop_resolution / args.crop_scale))),
        cropResolution=np.array((args.crop_resolution, args.crop_resolution)))

    # create output dir
    if not os.path.exists(args.out_dir):
        os.makedirs(args.out_dir)

    outputFile = open(args.landmark_file, 'w')

    t1 = time()
    while(True):
        ret, frame = cap.read()
        if not ret:
            break
        frameId += 1
        if frameId % (args.skip_frames + 1) != 0:
            continue

        # track and detect faces
        faces = tracker.processFrame(frame)

        for k, face in faces:
            saveFaces(outputFile, frameId, k, face)

        alignedFaces = []
        for k, face in faces:
            H = aligner.getTranformation(face)
            crop = aligner.transform(frame, H)
            alignedFaces.append((k, crop))

        for k, crop in alignedFaces:
            crop_name = 'face_{:06d}_{:04d}.jpg'.format(frameId, k)
            cv2.imwrite(
                os.path.join(args.out_dir, crop_name),
                crop, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
    print('DONE with average fps: ', frameId / (time()-t1))

    outputFile.close()
    cap.release()

if __name__ == "__main__":
    main()


text:
/*
 * A simple wrapper around a file handle. Throws exceptions in
 * case of errors. Moves the file handle when copied.
 *
 * @exception_safe: strong
 * @thread_safe: unknown
 */

#ifndef UPS_FILE_H
#define UPS_FILE_H

#include "0root/root.h"
#include "1base/mutex.h"

#include <stdio.h>
#include <limits.h>

#include "ups/types.h"

// Always verify that a file of level N does not include headers > N!
#include "1os/os.h"

#ifndef UPS_ROOT_H
#  error "root.h was not included"
#endif

namespace upscaledb {

class File
{
  public:
    enum {
#ifdef UPS_OS_POSIX
      kSeekSet = SEEK_SET,
      kSeekEnd = SEEK_END,
      kSeekCur = SEEK_CUR,
      kMaxPath = PATH_MAX
#else
      kSeekSet = FILE_BEGIN,
      kSeekEnd = FILE_END,
      kSeekCur = FILE_CURRENT,
      kMaxPath = MAX_PATH
#endif
    };

    // Constructor: creates an empty File handle
    File()
      : m_fd(UPS_INVALID_FD), m_mmaph(UPS_INVALID_FD), m_posix_advice(0) {
    }

    // Copy constructor: moves ownership of the file handle
    File(File &other)
      : m_fd(other.m_fd), m_mmaph(other.m_mmaph),
        m_posix_advice(other.m_posix_advice) {
      other.m_fd = UPS_INVALID_FD;
	  other.m_mmaph = UPS_INVALID_FD;
    }

    // Move constructor: moves ownership of the file handle
    File(File &&other)
      : m_fd(other.m_fd), m_mmaph(other.m_mmaph),
        m_posix_advice(other.m_posix_advice) {
      other.m_fd = UPS_INVALID_FD;
      other.m_mmaph = UPS_INVALID_FD;
    }

    // Assignment operator: moves ownership of the file handle
    template<typename T> // can bind to lvalue AND rvalue
    File &operator=(T &&other) {
      m_fd = other.m_fd;
      other.m_fd = UPS_INVALID_FD;
      return *this;
    }

    // Destructor: closes the file
    ~File() {
      close();
    }

    // Creates a new file
    void create(const char *filename, uint32_t mode);

    // Opens an existing file
    void open(const char *filename, bool read_only);

    // Returns true if the file is open
    bool is_open() const {
      return m_fd != UPS_INVALID_FD;
    }

    // Flushes a file
    void flush();

    // Sets the parameter for posix_fadvise()
    void set_posix_advice(int parameter);

    // Maps a file in memory
    //
    // mmap is called with MAP_PRIVATE - the allocated buffer
    // is just a copy of the file; writing to the buffer will not alter
    // the file itself.
    void mmap(uint64_t position, size_t size, bool readonly,
                    uint8_t **buffer);

    // Unmaps a buffer
    void munmap(void *buffer, size_t size);

    // Positional read from a file
    void pread(uint64_t addr, void *buffer, size_t len);

    // Positional write to a file
    void pwrite(uint64_t addr, const void *buffer, size_t len);

    // Write data to a file; uses the current file position
    void write(const void *buffer, size_t len);

    // Get the page allocation granularity of the operating system
    static size_t granularity();

    // Seek position in a file
    void seek(uint64_t offset, int whence) const;

    // Tell the position in a file
    uint64_t tell() const;

    // Returns the size of the file
    uint64_t file_size() const;

    // Truncate/resize the file
    void truncate(uint64_t newsize);

    // Closes the file descriptor
    void close();

  private:
    // The file handle
    ups_fd_t m_fd;

    // The mmap handle - required for Win32
    ups_fd_t m_mmaph;

    // Parameter for posix_fadvise()
    int m_posix_advice;

#ifdef WIN32
	// A mutex; required for Win32
	Mutex m_mutex;
#endif
};

} // namespace upscaledb

#endif /* UPS_FILE_H */


text:
ODK POST Receiver
=================

A simple appengine server that receives and displays JSON POST requests from ODK (OpenDataKit) Aggregate.

How to use
==========

If you are a running ODK Aggregate server, you can use this server to test the Z-Alpha JSON publisher.

Select 'Publish' next to any form and select Z-Alpha JSON publisher. Specify *http://odk-post-receiver.appspot.com* as the Server URL and leave the Authorization Token field empty.

![Screenshot of Z-Alpha JSON Publisher](http://imgur.com/4q2jcbK.png)

Once configured, the ODK Aggregate server will stream new form submissions as JSON POST requests to this server. If the ODK Aggregate server was configured correctly, you will see your form submissions listed at http://odk-post-receiver.appspot.com

**Note: All data will be automacally purged from the server within 1 hour.**

LICENSE
=======
Copyright 2014 Ujaval Gandhi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License