text:
// Our general strategy for preventing conflicts between concurrent
// reads and writes of resource variables is to:
// * For read operations, we:
//   - acquire the variable's mutex (in "shared" mode);
//   - make a (shallow) copy of the Tensor object, which increments
//     the reference count on the variable's TensorBuffer;
//   - release the variable's mutex;
//   - use the copy of the Tensor object to do the read.
// * For write operations, we:
//   - acquire the variable's mutex (in "exclusive" mode);
//   - check the reference count of variable's TensorBuffer and
//     if it is >1, make a deep copy of the variable's Tensor;
//   - mutate the variable's Tensor;
//   - and release the variable's mutex.
// This allows several read operations to all use the same
// TensorBuffer without needing to copy. When it comes time to write
// it will only make a copy if there is an outstanding read using the
// buffer. Write operations are serialized by the variable's mutex.
//
// For sparse operations (scatter, gather, sparse optimizer updates),
// we need to avoid copies, since there may not be enough memory for
// to copies of the whole tensor. To support this, we make two
// modifications to the above strategy:
// * For sparse reads (gather), we hold the variable's mutex (still in
//   "shared" mode) for the duration of the whole read. This means
//   that as long as you only do sparse read operations no write will
//   see the reference count >1.
// * For sparse write operations where the user explicitly specifies
//   that they want to perform the write without locks held
//   (use_locking=false), we never copy even if the variable's
//   reference count is >1.

#define EIGEN_USE_THREADS

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define EIGEN_USE_GPU
#include "tensorflow/core/common_runtime/gpu/gpu_event_mgr.h"
#include "tensorflow/core/platform/stream_executor.h"
#endif

#include <memory>
#include <vector>

#include "absl/strings/str_join.h"
#include "tensorflow/core/common_runtime/device.h"
#include "tensorflow/core/framework/bounds_check.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/resource_mgr.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/tensor_types.h"
#include "tensorflow/core/framework/variant_op_registry.h"
#include "tensorflow/core/kernels/dense_update_functor.h"
#include "tensorflow/core/kernels/gather_functor.h"
#include "tensorflow/core/kernels/gather_nd_op.h"
#include "tensorflow/core/kernels/resource_variable_ops.h"
#include "tensorflow/core/kernels/resource_variable_util.h"
#include "tensorflow/core/kernels/scatter_functor.h"
#include "tensorflow/core/kernels/training_op_helpers.h"
#include "tensorflow/core/kernels/variable_ops.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/refcount.h"
#include "tensorflow/core/platform/casts.h"
#include "tensorflow/core/platform/mem.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/util/determinism.h"
#include "tensorflow/core/util/util.h"

namespace tensorflow {

REGISTER_KERNEL_BUILDER(Name("_VarHandlesOp").Device(DEVICE_CPU),
                        ResourceHandlesOp<Var>);

ReadVariableOp::ReadVariableOp(OpKernelConstruction* c) : OpKernel(c) {
  OP_REQUIRES_OK(c, c->GetAttr("dtype", &dtype_));
}

namespace {

Status CopyVariable(int output_idx, OpKernelContext* ctx, const Tensor* t) {
  Tensor* output;
  Notification n;
  Status status;
  AllocatorAttributes attr;
  if (t->dtype() == DT_VARIANT) {
    attr.set_on_host(true);
  }
  TF_RETURN_IF_ERROR(
      ctx->allocate_output(output_idx, t->shape(), &output, attr));
  if (t->dtype() == DT_VARIANT) {
    output->flat<Variant>() = t->flat<Variant>();
  } else if (ctx->op_device_context() != nullptr) {
    // TODO(apassos): remove the down_cast by just returning Device* from
    // OpKernelContext
    Device* device = down_cast<Device*>(ctx->device());
    ctx->op_device_context()->CopyTensorInSameDevice(
        t, device, output, [&n, &status](const Status& s) {
          status = s;
          n.Notify();
        });
    n.WaitForNotification();
    return status;
  } else {
    switch (t->dtype()) {
#define HANDLER(type)                       \
  case DataTypeToEnum<type>::value:         \
    output->flat<type>() = t->flat<type>(); \
    break;
      TF_CALL_ALL_TYPES(HANDLER);
#undef HANDLER
      default:
        return errors::Internal("Unsupported dtype", t->dtype());
    }
  }
  return Status::OK();
}

}  // namespace

void ReadVariableOp::Compute(OpKernelContext* ctx) {
  core::RefCountPtr<Var> variable;
  const ResourceHandle& handle = HandleFromInput(ctx, 0);
  const auto status = LookupResource(ctx, handle, &variable);
  OP_REQUIRES(ctx, status.ok(),
              errors::FailedPrecondition(
                  "Could not find variable ", handle.name(), ". ",
                  "This could mean that the variable has been deleted. ",
                  "In TF1, it can also mean the variable is uninitialized. ",
                  "Debug info: container=", handle.container(),
                  ", status error message=", status.error_message()));

  tf_shared_lock ml(*variable->mu());
  // We're acquiring a reference to the underlying buffer while
  // holding a shared lock to guarantee ordering of reads and
  // writes when in copy-on-write mode.
  const Tensor* t = variable->tensor();
  if (!variable->copy_on_read_mode.load()) {
    OP_REQUIRES(
        ctx, dtype_ == t->dtype(),
        errors::InvalidArgument(
            "Trying to read variable with wrong dtype. Expected ",
            DataTypeString(dtype_), " got ", DataTypeString(t->dtype())));
    ctx->set_output(0, *t);
  } else {
    OP_REQUIRES_OK(ctx, CopyVariable(0, ctx, t));
  }
}

ReadVariablesOp::ReadVariablesOp(OpKernelConstruction* c) : OpKernel(c) {
  int n;
  OP_REQUIRES_OK(c, c->GetAttr("N", &n));
  OP_REQUIRES_OK(c, c->GetAttr("dtypes", &dtypes_));
  OP_REQUIRES(c, n == dtypes_.size(),
              errors::InvalidArgument(
                  "Mismatched number of arguments to ReadVariablesOp (", n,
                  " vs. ", dtypes_.size(), ")"));
}

void ReadVariablesOp::Compute(OpKernelContext* ctx) {
  std::vector<core::RefCountPtr<Var>> variables(dtypes_.size());
  std::vector<const ResourceHandle*> handles(dtypes_.size());
  for (size_t i = 0; i < dtypes_.size(); ++i) {
    handles[i] = &HandleFromInput(ctx, i);
  }

  OP_REQUIRES_OK(ctx, LookupResources(ctx, handles, &variables));

  std::vector<string> uninitialized_vars;
  for (int64_t i = 0; i < variables.size(); i++) {
    if (variables[i] == nullptr) {
      uninitialized_vars.push_back(handles[i]->name());
    }
  }

  OP_REQUIRES(ctx, uninitialized_vars.empty(),
              errors::FailedPrecondition(
                  "In ReadVariablesOp the following variables were "
                  "found uninitialized: ",
                  absl::StrJoin(uninitialized_vars, ", ")));

  for (size_t i = 0; i < dtypes_.size(); ++i) {
    // We're acquiring a reference to the underlying buffer while
    // holding a shared lock to guarantee ordering of reads and
    // writes.
    tf_shared_lock ml(*variables[i]->mu());
    OP_REQUIRES(ctx, dtypes_[i] == variables[i]->tensor()->dtype(),
                errors::InvalidArgument(
                    "Trying to read variable ", handles[i]->name(),
                    " from Container: ", handles[i]->container(),
                    " with wrong dtype. Expected ", DataTypeString(dtypes_[i]),
                    " got ", DataTypeString(variables[i]->tensor()->dtype())));
    if (variables[i]->copy_on_read_mode.load()) {
      OP_REQUIRES_OK(ctx, CopyVariable(i, ctx, variables[i]->tensor()));
    } else {
      const Tensor& t = *variables[i]->tensor();
      ctx->set_output(i, t);
    }
  }
}

REGISTER_KERNEL_BUILDER(Name("ReadVariableOp").Device(DEVICE_CPU),
                        ReadVariableOp);
REGISTER_KERNEL_BUILDER(Name("_ReadVariablesOp").Device(DEVICE_CPU),
                        ReadVariablesOp);

REGISTER_KERNEL_BUILDER(
    Name("ReadVariableOp").Device(DEVICE_DEFAULT).HostMemory("resource"),
    ReadVariableOp);
REGISTER_KERNEL_BUILDER(
    Name("_ReadVariablesOp").Device(DEVICE_DEFAULT).HostMemory("resources"),
    ReadVariablesOp);

VarHandleOp::VarHandleOp(OpKernelConstruction* context) : OpKernel(context) {
  OP_REQUIRES_OK(context, context->GetAttr("container", &container_));
  OP_REQUIRES_OK(context, context->GetAttr("shared_name", &name_));

  OP_REQUIRES_OK(context, context->GetAttr("dtype", &dtype_and_shape_.dtype));
  OP_REQUIRES_OK(context, context->GetAttr("shape", &dtype_and_shape_.shape));

  is_anonymous_ = name_ == ResourceHandle::ANONYMOUS_NAME;

  // Use const_tensor_ if the variable is non-anonymous.
  if (!is_anonymous_) {
    AllocatorAttributes attr;
    attr.set_on_host(true);
    OP_REQUIRES_OK(context, context->allocate_temp(DT_RESOURCE, TensorShape({}),
                                                   &const_tensor_, attr));
    const_tensor_.scalar<ResourceHandle>()() = MakeResourceHandle<Var>(
        context, container_, name_,
        std::vector<DtypeAndPartialTensorShape>{dtype_and_shape_});
  }
}

void VarHandleOp::Compute(OpKernelContext* ctx) {
  if (is_anonymous_) {
    Var* resource = new Var(dtype_and_shape_.dtype);
    ResourceMgr* mgr = ctx->resource_manager();
    ResourceHandle handle = ResourceHandle::MakeRefCountingHandle<Var>(
        resource, ctx->device()->name(),
        std::vector<DtypeAndPartialTensorShape>{dtype_and_shape_},
        ctx->stack_trace());
    // TODO(b/203901837): See if we can abolish all code paths that lookup
    // anonymous variables and then stop publishing them to the manager.
    OP_REQUIRES_OK(ctx, mgr->CreateUnowned<Var>(handle.container(),
                                                handle.name(), resource));

    AllocatorAttributes attr;
    attr.set_on_host(true);
    Tensor tensor;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_temp(DT_RESOURCE, TensorShape({}), &tensor, attr));

    tensor.scalar<ResourceHandle>()() = std::move(handle);

    ctx->set_output(0, tensor);
  } else {
    ctx->set_output(0, const_tensor_);
  }
}

REGISTER_KERNEL_BUILDER(Name("VarHandleOp").Device(DEVICE_CPU), VarHandleOp);

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define REGISTER_GPU_KERNELS(type)                             \
  namespace functor {                                          \
  template <>                                                  \
  void DenseUpdate<GPUDevice, type, ASSIGN>::operator()(       \
      const GPUDevice& d, typename TTypes<type>::Flat lhs,     \
      typename TTypes<type>::ConstFlat rhs);                   \
  extern template struct DenseUpdate<GPUDevice, type, ASSIGN>; \
  }

TF_CALL_GPU_ALL_TYPES(REGISTER_GPU_KERNELS);
TF_CALL_bfloat16(REGISTER_GPU_KERNELS);
TF_CALL_int64(REGISTER_GPU_KERNELS);
TF_CALL_variant(REGISTER_GPU_KERNELS);
TF_CALL_uint32(REGISTER_GPU_KERNELS);
#undef REGISTER_GPU_KERNELS

#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

#define REGISTER_DEFAULT_KERNELS(type)                        \
  REGISTER_KERNEL_BUILDER(Name("VarHandleOp")                 \
                              .Device(DEVICE_DEFAULT)         \
                              .HostMemory("resource")         \
                              .TypeConstraint<type>("dtype"), \
                          VarHandleOp)
TF_CALL_GPU_ALL_TYPES(REGISTER_DEFAULT_KERNELS);
TF_CALL_bfloat16(REGISTER_DEFAULT_KERNELS);
TF_CALL_int64(REGISTER_DEFAULT_KERNELS);
TF_CALL_variant(REGISTER_DEFAULT_KERNELS);
TF_CALL_uint32(REGISTER_DEFAULT_KERNELS);
#undef REGISTER_DEFAULT_KERNELS

REGISTER_KERNEL_BUILDER(Name("_VarHandlesOp")
                            .Device(DEVICE_DEFAULT)
                            .HostMemory("resources")
                            .TypeConstraint("dtypes",
                                            {DT_INT64, DT_COMPLEX64,
                                             DT_COMPLEX128, DT_HALF, DT_FLOAT,
                                             DT_DOUBLE, DT_BOOL, DT_VARIANT}),
                        ResourceHandlesOp<Var>);

REGISTER_KERNEL_BUILDER(
    Name("VariableShape").Device(DEVICE_CPU).TypeConstraint<int32>("out_type"),
    VariableShapeOp<int32>);
REGISTER_KERNEL_BUILDER(Name("VariableShape")
                            .Device(DEVICE_CPU)
                            .TypeConstraint<int64_t>("out_type"),
                        VariableShapeOp<int64_t>);

REGISTER_KERNEL_BUILDER(Name("VariableShape")
                            .Device(DEVICE_DEFAULT)
                            .TypeConstraint<int32>("out_type")
                            .HostMemory("output")
                            .HostMemory("input"),
                        VariableShapeOp<int32>);
REGISTER_KERNEL_BUILDER(Name("VariableShape")
                            .Device(DEVICE_DEFAULT)
                            .TypeConstraint<int64_t>("out_type")
                            .HostMemory("output")
                            .HostMemory("input"),
                        VariableShapeOp<int64_t>);

DestroyResourceOp::DestroyResourceOp(OpKernelConstruction* ctx)
    : OpKernel(ctx) {
  OP_REQUIRES_OK(ctx,
                 ctx->GetAttr("ignore_lookup_error", &ignore_lookup_error_));
}

void DestroyResourceOp::Compute(OpKernelContext* ctx) {
  const ResourceHandle& p = HandleFromInput(ctx, 0);
  Status status = DeleteResource(ctx, p);
  if (ignore_lookup_error_ && errors::IsNotFound(status)) {
    return;
  }
  OP_REQUIRES_OK(ctx, status);
}

REGISTER_KERNEL_BUILDER(Name("DestroyResourceOp").Device(DEVICE_CPU),
                        DestroyResourceOp);
REGISTER_KERNEL_BUILDER(
    Name("DestroyResourceOp").Device(DEVICE_DEFAULT).HostMemory("resource"),
    DestroyResourceOp);

void DisableCopyOnReadOp::Compute(OpKernelContext* ctx) {
  core::RefCountPtr<Var> variable;
  const ResourceHandle& handle = HandleFromInput(ctx, 0);
  const auto status = LookupResource(ctx, handle, &variable);
  OP_REQUIRES(ctx, status.ok(),
              errors::FailedPrecondition(
                  "Could not find variable ", handle.name(), ". ",
                  "This could mean that the variable has been deleted. ",
                  "In TF1, it can also mean the variable is uninitialized. ",
                  "Debug info: container=", handle.container(),
                  ", status error message=", status.error_message()));
  // If the variable is currently in copy-on-read mode, its refcount is 1
  if (variable->copy_on_read_mode.load()) {
    // Obtain an exclusive lock on the variable and change the access mode
    mutex_lock ml(*variable->mu());
    variable->copy_on_read_mode.store(false);
  }
}

REGISTER_KERNEL_BUILDER(Name("DisableCopyOnRead").Device(DEVICE_CPU),
                        DisableCopyOnReadOp);
REGISTER_KERNEL_BUILDER(
    Name("DisableCopyOnRead").Device(DEVICE_DEFAULT).HostMemory("resource"),
    DisableCopyOnReadOp);

template <typename Device, typename T>
class AssignVariableOp : public OpKernel {
 public:
  explicit AssignVariableOp(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("dtype", &dtype_));
    if (!c->GetAttr("_grappler_relax_allocator_constraints",
                    &relax_constraints_)
             .ok()) {
      relax_constraints_ = false;
    }
    if (c->HasAttr("validate_shape")) {
      OP_REQUIRES_OK(c, c->GetAttr("validate_shape", &validate_shape_));
    }
  }

  void Compute(OpKernelContext* context) override {
    OP_REQUIRES(context, dtype_ == context->input(1).dtype(),
                errors::InvalidArgument(
                    "Variable and value dtypes don't match; respectively, ",
                    DataTypeString(dtype_), " and ",
                    DataTypeString(context->input(1).dtype())));
    core::RefCountPtr<Var> variable;
    const Tensor& value = context->input(1);
    // Note: every resource-variable-manipulating op assumes copy-on-write
    // semantics, and creates a copy of the variable's Tensor if its refcount is
    // bigger than 1 when we try to modify it. This means we never need to copy
    // the original tensor for AssignVariableOp; even if there are other live
    // users of it we know none can modify it so this is always safe (even in
    // esoteric cases where the same tensor is used to initialize multiple
    // variables or the tensor is a constant this is safe, as future writes will
    // trigger copies).
    OP_REQUIRES_OK(context, LookupOrCreateResource<Var>(
                                context, HandleFromInput(context, 0), &variable,
                                [this, &value](Var** ptr) {
                                  *ptr = new Var(dtype_);
                                  *(*ptr)->tensor() = value;
                                  (*ptr)->is_initialized = true;
                                  return Status::OK();
                                }));
    mutex_lock ml(*variable->mu());
    // (variable->tensor()->dtype() == DT_INVALID && !variable->is_initialized)
    // check below is to allow an XLA specific situation wherein update can
    // happen first by the AssignVariableOp,
    // in which case the variable is still uninitialized.
    // When using TF-XLA, this scenario is possible when the execution uses the
    // 'fallback' path (which essentially invokes Tensorflow ops via
    // partitioned_call).
    OP_REQUIRES(context,
                (variable->tensor()->dtype() == DT_INVALID &&
                 !variable->is_initialized) ||
                    variable->tensor()->dtype() == dtype_,
                errors::InvalidArgument(
                    "Trying to assign variable with wrong dtype. Expected ",
                    DataTypeString(variable->tensor()->dtype()), " got ",
                    DataTypeString(dtype_)));
    if (validate_shape_) {
      OP_REQUIRES(
          context,
          (!variable->is_initialized ||
           variable->tensor()->shape().IsSameSize(value.shape())),
          errors::InvalidArgument(
              "Trying to assign to variable with tensor with wrong shape."
              " Expected ",
              variable->tensor()->shape().DebugString(), " got ",
              value.shape().DebugString()));
    }
    if (variable->copy_on_read_mode.load()) {
      AllocatorAttributes attr;
      attr.set_gpu_compatible(true);
      attr.set_nic_compatible(true);
      OP_REQUIRES_OK(context,
                     context->allocate_temp(value.dtype(), value.shape(),
                                            variable->tensor(), attr));
      functor::DenseUpdate<Device, T, ASSIGN> copy_functor;
      copy_functor(context->eigen_device<Device>(),
                   variable->tensor()->flat<T>(), value.flat<T>());
    } else {
      *variable->tensor() = value;
    }
    variable->is_initialized = true;
  }

 private:
  DataType dtype_;
  bool relax_constraints_;
  bool validate_shape_ = false;
};

template <typename Device>
class AssignVariableOp<Device, Variant> : public OpKernel {
 public:
  explicit AssignVariableOp(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("dtype", &dtype_));
    OP_REQUIRES(c, dtype_ == DT_VARIANT,
                errors::Internal("Variant kernel called with dtype: ",
                                 DataTypeString(dtype_)));
  }

  void Compute(OpKernelContext* context) override {
    const Tensor& value = context->input(1);
    core::RefCountPtr<Var> variable;
    OP_REQUIRES_OK(context, LookupOrCreateResource<Var>(
                                context, HandleFromInput(context, 0), &variable,
                                [](Var** ptr) {
                                  // Created on host.
                                  *ptr = new Var(DT_VARIANT);
                                  return Status::OK();
                                }));

    // For purposes of forwarding DT_VARIANT, we want the least
    // restrictive attr; we already know the input is on host.
    AllocatorAttributes attr;

    // Copying is unnecessary if we are the last user of the value
    // tensor, we can just adopt the input tensor's buffer instead.
    // Note that Variant objects themselves always reside on host.
    //
    // We nevertheless want to signal to the runtime that the tensor
    // should reside in memory of the associated device, as Variant
    // tensors may be marked as sitting on either CPU or GPU.  This
    // helps to elide one or more copies.
    std::unique_ptr<Tensor> input_alias = context->forward_input(
        1, OpKernelContext::Params::kNoReservation /*output_index*/, DT_VARIANT,
        value.shape(),
        DEVICE_MEMORY /* HOST_MEMORY is only reserved for special cases */,
        attr);

    mutex_lock ml(*variable->mu());
    OP_REQUIRES(context, variable->tensor()->dtype() == DT_VARIANT,
                errors::InvalidArgument(
                    "Trying to assign variable with wrong dtype. Expected ",
                    DataTypeString(variable->tensor()->dtype()), " got ",
                    DataTypeString(DT_VARIANT)));
    variable->is_initialized = true;
    *variable->tensor() = Tensor(DT_VARIANT, value.shape());

    if (input_alias) {
      *variable->tensor() = *input_alias;
      return;
    }

    // Need to copy, but maybe we can re-use variable's buffer?
    if (!variable->tensor()->RefCountIsOne() ||
        !variable->tensor()->shape().IsSameSize(value.shape())) {
      // Allocation of DT_VARIANT is always on host.
      attr.set_on_host(true);
      OP_REQUIRES_OK(context, context->allocate_temp(DT_VARIANT, value.shape(),
                                                     variable->tensor(), attr));
    }

    const auto elements_in = value.flat<Variant>();
    auto elements_out = variable->tensor()->flat<Variant>();
    for (int64_t i = 0; i < elements_in.size(); ++i) {
      elements_out(i) = elements_in(i);
    }
  }

 private:
  DataType dtype_;
};

#define REGISTER_KERNELS(type)                                \
  REGISTER_KERNEL_BUILDER(Name("AssignVariableOp")            \
                              .Device(DEVICE_CPU)             \
                              .TypeConstraint<type>("dtype"), \
                          AssignVariableOp<Eigen::ThreadPoolDevice, type>);

TF_CALL_ALL_TYPES(REGISTER_KERNELS);
TF_CALL_QUANTIZED_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define REGISTER_GPU_KERNELS(type)                           \
  REGISTER_KERNEL_BUILDER(Name("AssignVariableOp")           \
                              .Device(DEVICE_GPU)            \
                              .TypeConstraint<type>("dtype") \
                              .HostMemory("resource"),       \
                          AssignVariableOp<GPUDevice, type>);

TF_CALL_GPU_ALL_TYPES(REGISTER_GPU_KERNELS);
TF_CALL_bfloat16(REGISTER_GPU_KERNELS);
TF_CALL_int64(REGISTER_GPU_KERNELS);
TF_CALL_uint32(REGISTER_GPU_KERNELS);
#undef REGISTER_GPU_KERNELS
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

REGISTER_KERNEL_BUILDER(Name("AssignVariableOp")
                            .Device(DEVICE_DEFAULT)
                            .TypeConstraint<Variant>("dtype")
                            .HostMemory("resource"),
                        AssignVariableOp<CPUDevice, Variant>);

template <typename Device, typename T, DenseUpdateType Op>
class AssignUpdateVariableOp : public OpKernel {
 public:
  explicit AssignUpdateVariableOp(OpKernelConstruction* c) : OpKernel(c) {}

  void Compute(OpKernelContext* context) override {
    core::RefCountPtr<Var> variable;
    OP_REQUIRES_OK(context, LookupResource(context, HandleFromInput(context, 0),
                                           &variable));

    const Tensor& value = context->input(1);
    // TODO(apassos): We could possibly avoid the copy done by
    // PrepareToUpdateVariable() for commutative operations like Op ==
    // ADD if value's refcount was 1.
    mutex_lock ml(*variable->mu());
    Tensor* var_tensor = variable->tensor();
    OP_REQUIRES_OK(context, ValidateAssignUpdateVariableOpShapes(
                                var_tensor->shape(), value.shape()));
    OP_REQUIRES_OK(
        context, PrepareToUpdateVariable<Device, T>(
                     context, var_tensor, variable->copy_on_read_mode.load()));
    functor::DenseUpdate<Device, T, Op> update_functor;
    update_functor(context->eigen_device<Device>(), var_tensor->flat<T>(),
                   value.flat<T>());
  }
};

#define REGISTER_KERNELS(type)                                     \
  REGISTER_KERNEL_BUILDER(                                         \
      Name("AssignAddVariableOp")                                  \
          .Device(DEVICE_CPU)                                      \
          .TypeConstraint<type>("dtype"),                          \
      AssignUpdateVariableOp<Eigen::ThreadPoolDevice, type, ADD>); \
  REGISTER_KERNEL_BUILDER(                                         \
      Name("AssignSubVariableOp")                                  \
          .Device(DEVICE_CPU)                                      \
          .TypeConstraint<type>("dtype"),                          \
      AssignUpdateVariableOp<Eigen::ThreadPoolDevice, type, SUB>);

TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define REGISTER_GPU_KERNELS(type)                                       \
  REGISTER_KERNEL_BUILDER(Name("AssignAddVariableOp")                    \
                              .Device(DEVICE_GPU)                        \
                              .HostMemory("resource")                    \
                              .TypeConstraint<type>("dtype"),            \
                          AssignUpdateVariableOp<GPUDevice, type, ADD>); \
  REGISTER_KERNEL_BUILDER(Name("AssignSubVariableOp")                    \
                              .Device(DEVICE_GPU)                        \
                              .HostMemory("resource")                    \
                              .TypeConstraint<type>("dtype"),            \
                          AssignUpdateVariableOp<GPUDevice, type, SUB>);

TF_CALL_GPU_NUMBER_TYPES(REGISTER_GPU_KERNELS);
TF_CALL_int64(REGISTER_GPU_KERNELS);
#undef REGISTER_GPU_KERNELS
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

class VarIsInitializedOp : public OpKernel {
 public:
  explicit VarIsInitializedOp(OpKernelConstruction* c) : OpKernel(c) {}

  void Compute(OpKernelContext* context) override {
    Tensor* output = nullptr;
    OP_REQUIRES_OK(context,
                   context->allocate_output(0, TensorShape({}), &output));
    auto output_tensor = output->tensor<bool, 0>();
    core::RefCountPtr<Var> variable;
    Status s = LookupResource(context, HandleFromInput(context, 0), &variable);
    if (!s.ok()) {
      output_tensor() = false;
      return;
    }
    mutex_lock ml(*variable->mu());
    output_tensor() = variable->is_initialized;
  }
};

REGISTER_KERNEL_BUILDER(Name("VarIsInitializedOp").Device(DEVICE_CPU),
                        VarIsInitializedOp);

REGISTER_KERNEL_BUILDER(Name("VarIsInitializedOp")
                            .Device(DEVICE_DEFAULT)
                            .HostMemory("resource")
                            .HostMemory("is_initialized"),
                        VarIsInitializedOp);

template <typename Device, typename T, typename Index>
class ResourceGatherOp : public OpKernel {
 public:
  explicit ResourceGatherOp(OpKernelConstruction* c) : OpKernel(c) {
    OP_REQUIRES_OK(c, c->GetAttr("batch_dims", &batch_dims_));
  }

  void Compute(OpKernelContext* c) override {
    core::RefCountPtr<Var> v;
    OP_REQUIRES_OK(c, LookupResource(c, HandleFromInput(c, 0), &v));
    OP_REQUIRES_OK(c, EnsureSparseVariableAccess<Device, T>(c, v.get()));
    // NOTE: We hold the lock for the whole gather operation instead
    // of increasing the reference count of v->tensor() to avoid a
    // situation where a write to the same variable will see a
    // reference count greater than one and make a copy of the
    // (potentially very large) tensor buffer.
    tf_shared_lock ml(*v->mu());
    const Tensor& params = *v->tensor();
    const Tensor& indices = c->input(1);
    OP_REQUIRES(
        c, TensorShapeUtils::IsVectorOrHigher(params.shape()),
        errors::InvalidArgument("params must be at least 1 dimensional"));
    OP_REQUIRES(
        c, params.shape().dims() >= batch_dims_,
        errors::InvalidArgument("params must have at least ", batch_dims_,
                                " (batch_dims) dimensions but it has shape ",
                                params.shape().DebugString()));

    // Check that we have enough index space
    const int64_t N = indices.NumElements();
    OP_REQUIRES(
        c, params.dim_size(0) <= std::numeric_limits<Index>::max(),
        errors::InvalidArgument("params.shape[0] too large for ",
                                DataTypeString(DataTypeToEnum<Index>::v()),
                                " indexing: ", params.dim_size(0), " > ",
                                std::numeric_limits<Index>::max()));

    // The result shape is params.shape[:batch_dims] +
    // indices.shape[batch_dims:] + params.shape[batch_dims+1:].
    TensorShape result_shape;
    for (int i = 0; i < batch_dims_; ++i) {
      result_shape.AddDim(params.dim_size(i));
    }
    for (int i = batch_dims_; i < indices.dims(); ++i) {
      result_shape.AddDim(indices.dim_size(i));
    }
    for (int i = batch_dims_ + 1; i < params.dims(); ++i) {
      result_shape.AddDim(params.dim_size(i));
    }

    Tensor* out = nullptr;
    Tensor tmp;
    if (params.dtype() == DT_VARIANT) {
      tmp = Tensor(DT_VARIANT, result_shape);
      c->set_output(0, tmp);
      out = &tmp;
    } else {
      OP_REQUIRES_OK(c, c->allocate_output(0, result_shape, &out));
    }

    if (N > 0) {
      Tensor tmp_indices;

      // Points to the original or updated (if batch_dims is set) indices.
      const Tensor* op_indices = &indices;
      if (batch_dims_ > 0) {
        OP_REQUIRES_OK(c, c->allocate_temp(indices.dtype(), indices.shape(),
                                           &tmp_indices));
        functor::DenseUpdate<Device, Index, ASSIGN> copy_functor;
        copy_functor(c->eigen_device<Device>(), tmp_indices.flat<Index>(),
                     indices.flat<Index>());

        AddBatchOffsets(c, &tmp_indices, params);
        if (!c->status().ok()) return;
        op_indices = &tmp_indices;
      }

      int64_t gather_dim_size = 1;
      for (int idx = 0; idx <= batch_dims_; ++idx) {
        gather_dim_size *= params.dim_size(idx);
      }
      int64_t inner_size = 1;
      for (int i = batch_dims_ + 1; i < params.dims(); ++i) {
        inner_size *= params.dim_size(i);
      }
      auto params_flat = params.shaped<T, 3>({1, gather_dim_size, inner_size});
      const auto indices_flat = op_indices->flat<Index>();
      auto out_flat = out->shaped<T, 3>({1, N, out->NumElements() / N});

      functor::GatherFunctor<Device, T, Index> functor;
      int64_t bad_i = functor(c, params_flat, indices_flat, out_flat);

      OP_REQUIRES(
          c, bad_i < 0,
          errors::InvalidArgument(
              "indices", SliceDebugString(indices.shape(), bad_i), " = ",
              indices_flat(bad_i), " is not in [0, ", params.dim_size(0), ")"));
    }
  }

 private:
  // Add the batch offset derived from params to each batch of indices.
  // Example: batch_dims = 1, indices = [[0, 1, 2], [0, 1, 2]]
  // If indexing into a params dimension of size 4, then the indices will become
  // [0, 1, 2, 4, 5, 6]
  void AddBatchOffsets(OpKernelContext* ctx, Tensor* indices,
                       const Tensor& params) {
    int64_t batch_size = 1;  // The size of all batch dimensions.
    for (int idx = 0; idx < batch_dims_; ++idx) {
      batch_size *= params.dim_size(idx);
    }
    OP_REQUIRES(
        ctx, batch_size != 0,
        errors::InvalidArgument(
            "Inner size of indices would result in batch_size of 0 and a ",
            "division by 0 in the implementation. This is illegal"));

    auto indices_flat = indices->flat<Index>();
    int64_t const index_inner_size = indices->NumElements() / batch_size;
    int64_t const batch_offset = params.dim_size(batch_dims_);
    for (int64_t batch_idx = 0, dest_idx = 0; batch_idx < batch_size;
         ++batch_idx) {
      for (int64_t idx = 0; idx < index_inner_size; ++idx) {
        indices_flat(dest_idx++) += batch_offset * batch_idx;
      }
    }
  }

  int32 batch_dims_ = 0;
};

#define REGISTER_GATHER_FULL(dev, type, index_type)                    \
  REGISTER_KERNEL_BUILDER(Name("ResourceGather")                       \
                              .Device(DEVICE_##dev)                    \
                              .HostMemory("resource")                  \
                              .TypeConstraint<type>("dtype")           \
                              .TypeConstraint<index_type>("Tindices"), \
                          ResourceGatherOp<dev##Device, type, index_type>)

#define REGISTER_GATHER_ALL_INDICES(dev, type) \
  REGISTER_GATHER_FULL(dev, type, int32);      \
  REGISTER_GATHER_FULL(dev, type, int64_t)

#define REGISTER_GATHER_CPU(type) REGISTER_GATHER_ALL_INDICES(CPU, type)

// Registration of the CPU implementations.
TF_CALL_ALL_TYPES(REGISTER_GATHER_CPU);
TF_CALL_QUANTIZED_TYPES(REGISTER_GATHER_CPU);

// Registers GPU kernels.
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define REGISTER_GATHER_GPU(type) REGISTER_GATHER_ALL_INDICES(GPU, type)

TF_CALL_int64(REGISTER_GATHER_GPU);
TF_CALL_GPU_ALL_TYPES(REGISTER_GATHER_GPU);

// Variant objects themselves sit on CPU, even if they contain data
// pointing to a device.
REGISTER_KERNEL_BUILDER(Name("ResourceGather")
                            .Device(DEVICE_DEFAULT)
                            .HostMemory("resource")
                            .HostMemory("indices")
                            .TypeConstraint<Variant>("dtype")
                            .TypeConstraint<int32>("Tindices"),
                        ResourceGatherOp<CPUDevice, Variant, int32>)
REGISTER_KERNEL_BUILDER(Name("ResourceGather")
                            .Device(DEVICE_DEFAULT)
                            .HostMemory("resource")
                            .HostMemory("indices")
                            .TypeConstraint<Variant>("dtype")
                            .TypeConstraint<int64_t>("Tindices"),
                        ResourceGatherOp<CPUDevice, Variant, int64>)

#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

#undef REGISTER_GATHER_CPU
#undef REGISTER_GATHER_GPU
#undef REGISTER_GATHER_ALL_INDICES
#undef REGISTER_GATHER_FULL

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

  void Compute(OpKernelContext* c) override {
    core::RefCountPtr<Var> v;
    OP_REQUIRES_OK(c, LookupResource(c, HandleFromInput(c, 0), &v));
    OP_REQUIRES_OK(c, EnsureSparseVariableAccess<Device, T>(c, v.get()));
    // NOTE: We hold the lock for the whole gather operation instead
    // of increasing the reference count of v->tensor() to avoid a
    // situation where a write to the same variable will see a
    // reference count greater than one and make a copy of the
    // (potentially very large) tensor buffer.
    tf_shared_lock ml(*v->mu());
    const Tensor& params = *v->tensor();
    const Tensor& indices = c->input(1);

    Tensor out;
    OP_REQUIRES_OK(
        c, functor::DoGatherNd<Device, T, Index>(c, params, indices, &out));
    c->set_output(0, out);
  }
};

#define REGISTER_GATHER_ND_FULL(dev, type, index_type)                 \
  REGISTER_KERNEL_BUILDER(Name("ResourceGatherNd")                     \
                              .Device(DEVICE_##dev)                    \
                              .HostMemory("resource")                  \
                              .TypeConstraint<type>("dtype")           \
                              .TypeConstraint<index_type>("Tindices"), \
                          ResourceGatherNdOp<dev##Device, type, index_type>)

#define REGISTER_GATHER_ND_ALL_INDICES(dev, type) \
  REGISTER_GATHER_ND_FULL(dev, type, int32);      \
  REGISTER_GATHER_ND_FULL(dev, type, int64_t)

#define REGISTER_GATHER_ND_CPU(type) REGISTER_GATHER_ND_ALL_INDICES(CPU, type)

// Registration of the CPU implementations.
TF_CALL_ALL_TYPES(REGISTER_GATHER_ND_CPU);

// Registers GPU kernels.
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define REGISTER_GATHER_ND_GPU(type) REGISTER_GATHER_ND_ALL_INDICES(GPU, type)

TF_CALL_GPU_NUMBER_TYPES(REGISTER_GATHER_ND_GPU);

#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

#undef REGISTER_GATHER_ND_CPU
#undef REGISTER_GATHER_ND_GPU
#undef REGISTER_GATHER_ND_ALL_INDICES
#undef REGISTER_GATHER_ND_FULL

namespace {

template <typename Device>
bool isCPUDevice() {
  return false;
}

template <>
bool isCPUDevice<CPUDevice>() {
  return true;
}

template <typename T>
bool ValidateInput(const Tensor& updates) {
  const auto updates_flat = updates.flat<T>();
  for (int i = 0; i < updates.NumElements(); ++i) {
    if (updates_flat(i) == T{}) return false;
  }
  return true;
}

template <>
bool ValidateInput<Variant>(const Tensor& updates) {
  return true;
}

template <typename Device, typename T, typename Index, scatter_op::UpdateOp op>
Status DoScatter(OpKernelContext* c, Tensor* params, const Tensor& indices,
                 const Tensor& updates, Index num_indices);

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM

template <typename T>
Status CopyTensorToHost(OpKernelContext* c, const Tensor& device_tensor,
                        Tensor* host_tensor) {
  AllocatorAttributes alloc_attr;
  alloc_attr.set_on_host(true);
  alloc_attr.set_gpu_compatible(true);
  auto stream = c->op_device_context()->stream();
  TF_RETURN_IF_ERROR(c->allocate_temp(
      device_tensor.dtype(), device_tensor.shape(), host_tensor, alloc_attr));
  se::DeviceMemoryBase device_ptr(
      const_cast<Tensor&>(device_tensor).flat<T>().data(),
      device_tensor.flat<T>().size() * sizeof(T));
  stream->ThenMemcpy(host_tensor->flat<T>().data(), device_ptr,
                     device_tensor.NumElements() * sizeof(T));
  if (!stream) {
    return errors::Internal("Failed to copy indices to host");
  }
  return Status::OK();
}

// Copies inputs to the CPU, runs DoScatter on the CPU, then copies output
// back to GPU. This is useful because the CPU implementation is deterministic
// and the GPU implementation is not. Tensor inputs to this function must be on
// the GPU.
template <typename T, typename Index, scatter_op::UpdateOp Op>
Status DoScatterOnCpu(OpKernelContext* c, Tensor* params, const Tensor& indices,
                      const Tensor& updates, Index num_indices) {
  auto stream = c->op_device_context()->stream();

  Tensor host_indices;
  TF_RETURN_IF_ERROR(CopyTensorToHost<Index>(c, indices, &host_indices));
  Tensor host_updates;
  TF_RETURN_IF_ERROR(CopyTensorToHost<T>(c, updates, &host_updates));
  Tensor host_params;
  TF_RETURN_IF_ERROR(CopyTensorToHost<T>(c, *params, &host_params));

  TF_RETURN_IF_ERROR(stream->BlockHostUntilDone());
  TF_RETURN_IF_ERROR(DoScatter<CPUDevice, T, Index, Op>(
      c, &host_params, host_indices, host_updates, num_indices));

  // Copy 'host_params' to device.
  se::DeviceMemoryBase params_ptr(params->flat<T>().data(),
                                  params->flat<T>().size() * sizeof(T));
  stream->ThenMemcpy(&params_ptr, host_params.flat<T>().data(),
                     host_params.NumElements() * sizeof(T));
  if (!stream) {
    return errors::Internal("Failed to copy params to device");
  }
  // Deallocate host_params' buffer once the host-to-device copy is complete.
  // host_params is captured by value in the lambda so that its buffer is only
  // destructed once the lambda is destructed.
  c->device()->tensorflow_accelerator_device_info()->event_mgr->ThenExecute(
      stream, [host_params] {});
  return Status::OK();
}

#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

template <typename Device, typename T, typename Index, scatter_op::UpdateOp op>
Status DoScatter(OpKernelContext* c, Tensor* params, const Tensor& indices,
                 const Tensor& updates, Index num_indices) {
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
  if (std::is_same<Device, GPUDevice>::value &&
      tensorflow::OpDeterminismRequired()) {
    if (!DataTypeCanUseMemcpy(params->dtype())) {
      return errors::Unimplemented(
          "GPU Scatter ops for dtype ", DataTypeString(params->dtype()),
          " do not yet have a deterministic implementation");
    }
    return DoScatterOnCpu<T, Index, op>(c, params, indices, updates,
                                        num_indices);
  }
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
  auto indices_flat = indices.flat<Index>();
  auto params_flat = params->flat_outer_dims<T>();
  int64_t num_updates = updates.NumElements();
  auto updates_flat =
      updates.shaped<T, 2>({num_indices, num_updates / num_indices});
  functor::ScatterFunctor<Device, T, Index, op> functor;
  const Index bad_i = functor(c, c->template eigen_device<Device>(),
                              params_flat, updates_flat, indices_flat);
  if (bad_i >= 0) {
    return errors::InvalidArgument(
        "indices", SliceDebugString(indices.shape(), bad_i), " = ",
        indices_flat(bad_i), " is not in [0, ", params->dim_size(0), ")");
  }
  return Status::OK();
}

}  // namespace

template <typename Device, typename T, typename Index, scatter_op::UpdateOp op>
class ResourceScatterUpdateOp : public OpKernel {
 public:
  explicit ResourceScatterUpdateOp(OpKernelConstruction* c) : OpKernel(c) {
    // We use the same kernel for many operations.
    // Each operation has a different set of attributes defined in its nodes.
    Status s = c->GetAttr("use_locking", &use_exclusive_lock_);
    if (!s.ok()) {
      use_exclusive_lock_ = false;
    }
  }

  void Compute(OpKernelContext* c) override {
    core::RefCountPtr<Var> v;
    OP_REQUIRES_OK(c, LookupResource(c, HandleFromInput(c, 0), &v));
    OP_REQUIRES_OK(c, EnsureSparseVariableAccess<Device, T>(c, v.get()));
    const bool is_non_pod_dtype = c->input_dtype(0) == DT_RESOURCE ||
                                  c->input_dtype(0) == DT_STRING ||
                                  c->input_dtype(0) == DT_VARIANT;
    if (is_non_pod_dtype || use_exclusive_lock_) {
      mutex_lock ml(*v->mu());
      DoCompute(c);
    } else {
      // For POD dtypes, we can safely run the update without the mutex.
      tf_shared_lock ml(*v->mu());
      DoCompute(c);
    }
  }

 private:
  bool use_exclusive_lock_;

  void DoCompute(OpKernelContext* c) {
    core::RefCountPtr<Var> v;
    OP_REQUIRES_OK(c, LookupResource(c, HandleFromInput(c, 0), &v));
    Tensor* params = v->tensor();
    const Tensor& indices = c->input(1);
    const Tensor& updates = c->input(2);

    // Check that rank(updates.shape) = rank(indices.shape + params.shape[1:])
    OP_REQUIRES(c,
                updates.dims() == 0 ||
                    updates.dims() == indices.dims() + params->dims() - 1,
                errors::InvalidArgument(
                    "Must have updates.shape = indices.shape + "
                    "params.shape[1:] or updates.shape = [], got ",
                    "updates.shape ", updates.shape().DebugString(),
                    ", indices.shape ", indices.shape().DebugString(),
                    ", params.shape ", params->shape().DebugString()));

    // Check that we have enough index space
    const int64_t N_big = indices.NumElements();
    OP_REQUIRES(
        c, N_big <= std::numeric_limits<Index>::max(),
        errors::InvalidArgument("indices has too many elements for ",
                                DataTypeString(DataTypeToEnum<Index>::v()),
                                " indexing: ", N_big, " > ",
                                std::numeric_limits<Index>::max()));
    const Index N = static_cast<Index>(N_big);
    OP_REQUIRES(
        c, params->dim_size(0) <= std::numeric_limits<Index>::max(),
        errors::InvalidArgument("params.shape[0] too large for ",
                                DataTypeString(DataTypeToEnum<Index>::v()),
                                " indexing: ", params->dim_size(0), " > ",
                                std::numeric_limits<Index>::max()));

    // Prevent division by 0
    if (isCPUDevice<Device>() && op == tensorflow::scatter_op::UpdateOp::DIV) {
      OP_REQUIRES(c, ValidateInput<T>(updates),
                  errors::InvalidArgument("updates must not contain 0"));
    }

    if (N > 0) {
      auto indices_flat = indices.flat<Index>();
      auto params_flat = params->flat_outer_dims<T>();
      if (TensorShapeUtils::IsScalar(updates.shape())) {
        const auto update = updates.scalar<T>();

        functor::ScatterScalarFunctor<Device, T, Index, op> functor;
        const Index bad_i = functor(c, c->template eigen_device<Device>(),
                                    params_flat, update, indices_flat);
        OP_REQUIRES(c, bad_i < 0,
                    errors::InvalidArgument(
                        "indices", SliceDebugString(indices.shape(), bad_i),
                        " = ", indices_flat(bad_i), " is not in [0, ",
                        params->dim_size(0), ")"));
      } else {
        OP_REQUIRES(
            c, TensorShapeUtils::StartsWith(updates.shape(), indices.shape()),
            errors::InvalidArgument(
                "The shape of indices (", indices.shape().DebugString(),
                ") must be a prefix of the shape of updates (",
                updates.shape().DebugString(), ")"));
        OP_REQUIRES_OK(
            c, DoScatter<Device, T, Index, op>(c, params, indices, updates, N));
      }
    }
  }
};

#define REGISTER_SCATTER_KERNEL_INDEX(type, index_type, dev, name, op) \
  REGISTER_KERNEL_BUILDER(                                             \
      Name(name)                                                       \
          .Device(DEVICE_##dev)                                        \
          .HostMemory("resource")                                      \
          .TypeConstraint<type>("dtype")                               \
          .TypeConstraint<index_type>("Tindices"),                     \
      ResourceScatterUpdateOp<dev##Device, type, index_type, op>)

#define REGISTER_SCATTER_KERNEL(type, dev, name, op)         \
  REGISTER_SCATTER_KERNEL_INDEX(type, int32, dev, name, op); \
  REGISTER_SCATTER_KERNEL_INDEX(type, int64_t, dev, name, op);

#define REGISTER_SCATTER_ARITHMETIC(type, dev)                \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterAdd",    \
                          scatter_op::UpdateOp::ADD);         \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterSub",    \
                          scatter_op::UpdateOp::SUB);         \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterMul",    \
                          scatter_op::UpdateOp::MUL);         \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterDiv",    \
                          scatter_op::UpdateOp::DIV);         \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterUpdate", \
                          scatter_op::UpdateOp::ASSIGN);
#define REGISTER_SCATTER_MINMAX(type, dev)                 \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterMin", \
                          scatter_op::UpdateOp::MIN);      \
  REGISTER_SCATTER_KERNEL(type, dev, "ResourceScatterMax", \
                          scatter_op::UpdateOp::MAX);

// Registers CPU kernels.
#define REGISTER_SCATTER_ARITHMETIC_CPU(type) \
  REGISTER_SCATTER_ARITHMETIC(type, CPU);
#define REGISTER_SCATTER_MINMAX_CPU(type) REGISTER_SCATTER_MINMAX(type, CPU);

TF_CALL_NUMBER_TYPES(REGISTER_SCATTER_ARITHMETIC_CPU);
TF_CALL_REAL_NUMBER_TYPES(REGISTER_SCATTER_MINMAX_CPU);

REGISTER_SCATTER_KERNEL(tstring, CPU, "ResourceScatterUpdate",
                        scatter_op::UpdateOp::ASSIGN);
REGISTER_SCATTER_KERNEL(bool, CPU, "ResourceScatterUpdate",
                        scatter_op::UpdateOp::ASSIGN);
REGISTER_SCATTER_KERNEL(Variant, CPU, "ResourceScatterUpdate",
                        scatter_op::UpdateOp::ASSIGN);

// Registers GPU kernels.
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
#define REGISTER_SCATTER_ARITHMETIC_GPU(type) \
  REGISTER_SCATTER_ARITHMETIC(type, GPU);
#define REGISTER_SCATTER_MINMAX_GPU(type) REGISTER_SCATTER_MINMAX(type, GPU);

#define REGISTER_SCATTER_UPDATE_GPU(type) REGISTER_SCATTER_UPDATE(type, GPU);

TF_CALL_GPU_NUMBER_TYPES(REGISTER_SCATTER_ARITHMETIC_GPU);
TF_CALL_GPU_NUMBER_TYPES(REGISTER_SCATTER_MINMAX_GPU);

REGISTER_KERNEL_BUILDER(Name("ResourceScatterUpdate")
                            .Device(DEVICE_DEFAULT)
                            .HostMemory("resource")
                            .HostMemory("indices")
                            .TypeConstraint<Variant>("dtype")
                            .TypeConstraint<int32>("Tindices"),
                        ResourceScatterUpdateOp<CPUDevice, Variant, int32,
                                                scatter_op::UpdateOp::ASSIGN>)
REGISTER_KERNEL_BUILDER(Name("ResourceScatterUpdate")
                            .Device(DEVICE_GPU)
                            .HostMemory("resource")
                            .TypeConstraint<bool>("dtype")
                            .TypeConstraint<int32>("Tindices"),
                        ResourceScatterUpdateOp<GPUDevice, bool, int32,
                                                scatter_op::UpdateOp::ASSIGN>)
REGISTER_KERNEL_BUILDER(Name("ResourceScatterUpdate")
                            .Device(DEVICE_DEFAULT)
                            .HostMemory("resource")
                            .HostMemory("indices")
                            .TypeConstraint<Variant>("dtype")
                            .TypeConstraint<int64_t>("Tindices"),
                        ResourceScatterUpdateOp<CPUDevice, Variant, int64,
                                                scatter_op::UpdateOp::ASSIGN>)
REGISTER_KERNEL_BUILDER(Name("ResourceScatterUpdate")
                            .Device(DEVICE_GPU)
                            .HostMemory("resource")
                            .TypeConstraint<int64_t>("dtype")
                            .TypeConstraint<int64_t>("Tindices"),
                        ResourceScatterUpdateOp<GPUDevice, int64, int64,
                                                scatter_op::UpdateOp::ASSIGN>)

#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

#undef REGISTER_SCATTER_ARITHMETIC
#undef REGISTER_SCATTER_ARITHMETIC_CPU
#undef REGISTER_SCATTER_MINMAX
#undef REGISTER_SCATTER_MINMAX_CPU
#undef REGISTER_SCATTER_KERNEL
#undef REGISTER_SCATTER_KERNEL_INDEX

}  // namespace tensorflow

redpajama_set_name: RedPajamaGithub


Eric Schwarz is the founding CEO of Citizen Schools.
From The Opportunity Equation by Eric Schwarz, Copyright © 2014 Eric Schwarz. Reprinted by permission of Beacon Press, Boston.
Of all the questions I get about Citizen Schools, perhaps the most frequent is: "Do the teachers like you?" Many questioners seem conditioned to expect the worst of public school teachers and assume that a second shift of educators, offering different approaches and taking less or no pay, will inspire resentment from the full-time teachers who lead classes for a majority of the day.
Generally, however, America's teachers have embraced Citizen Schools and embraced an expanded learning day and citizen power in their schools. While a few teachers may react defensively and hide behind the closed door of their classroom, the best teachers welcome any help they can get. Teacher unions such as the American Federation of Teachers (Weingarten 2011) and the Boston Teacher's Union (2011) have also generally embraced Citizen Schools.
Adding a second shift of educators in schools could fundamentally change the teacher's job for the better, making it more sustainable and enjoyable while bringing more resources to kids and engaging families more deeply in their child's education. Suburban teachers often get this support from active families and well-organized extended-day programs. But most teachers in high-poverty schools feel overworked, undersupported, and unsuccessful. As a result, many of them leave teaching too soon, creating a higher-than-necessary teacher churn and more challenges for students (Ronfeldt, Loeb & Wyckoff 2013).
At the Isaac Newton School in East Harlem, New York, sixth-grade teacher David McKinney can teach his math class every morning knowing that every student in his class has done their homework from the previous day, because every student participates in the extended day with Citizen Schools and gets an hour of supported homework time from a second-shift teacher while still at school. Imagine this difference alone: Before Expanded Learning Time (ELT) maybe half of your students completed their homework, since many had no structured time and place to complete it. Now all of your students, or almost all of them, complete it. Imagine how that changes your job as a teacher.
Increasingly, Citizen Schools ELT schools include a thirty- to sixty-minute block where first-shift and second-shift teachers lead a class together. At Elmhurst Community Prep in Oakland, which in 2012-2013 had the most student learning growth of any middle school in the city, the teachers and teaching fellows co-teach an advisory block focused on goal-setting and on increasing students' ownership for their own success. Most days each adult in the room takes an advisory group of ten to twelve students, allowing students and adults alike to build meaningful relationships and trust, a sort of school-based social capital that often helps students advance. When students get better at asking for help, at speaking up when they don't understand something, and at holding give-and-take conversations with adults and peers, they are better positioned to move forward academically, socially, and professionally.
Allowing teachers time for pull-out tutoring, giving students extra academic practice time, and engaging parents in their child's learning are all important ways that Citizen Schools supports teachers. But the most important way we support teachers is by motivating students to try harder in school. By exposing students to exciting real-world projects, Citizen Schools helps make traditional school subjects become more relevant and enticing. All of a sudden a topic sentence becomes a key skill to win a mock trial, not just another academic standard on a long list that needs to be mastered. A student becomes motivated to learn the Pythagorean theorem because it helps unlock the secret of programming a video game.
Citizen Schools also supports teachers by allowing them to be mentors and master educators. With a second shift of eager young educators on the scene, experienced full-time teachers can not only get help in the classroom, but can give help by mentoring the young teaching fellows sourced by Citizen Schools.
"We had a teacher who taught English and who was really skilled at ELL (English language learner) instruction techniques. She was often in the classroom when we were teaching, and she ended up working with our Academic Program Lead to help her rewrite some of the lessons to better align with where she saw gaps in student learning and with how she taught in her class. We rearranged our staffing so that our three teaching fellows who worked most often with ELL students could observe her teaching. It was great, because it showed students that we were all colleagues and that the teachers and Citizen Schools staff were in it together. It was great for the teacher to see the planning that went into our programming and to have input into our instruction. And of course it was fabulous for our staff to have great techniques modeled by a pro.
ELT also provides teachers with a pathway to leadership, often a tough road in schools where the typical management structure for a school of 600 students is one principal, one assistant principal, a director of instruction or dean of discipline, a secretary, and fifty teachers. In the second and third years of ELT at her school in Redwood City, California, Sara Sheckel actually split her time between the school, where she taught two instead of four classes, and Citizen Schools, where she served as the part-time instructional coach, providing feedback and professional development to the first- and second-year educators in the teaching fellowship. The experience allowed her to continue adding value as a teacher while building management skills, ultimately leading to Sheckel's appointment for the 2013-2014 year as assistant principal of the Roy Cloud K–8 school in another part of Redwood City.
In many ways, the job of teacher as currently constructed is an outmoded relic of an industrial age. The teacher works mostly alone, putting equal attention into tasks he or she is great at and ones he or she struggles with. The job in year one is similar to the job in year ten or year forty. Just as students are treated too much like widgets in a factory, receiving the same dosage of multiplication tables and the same serving of Mendel's peas, regardless of their understanding and interest, teachers are asked to teach the same topics and in basically the same way regardless of their skill and experience and the needs of their students. It's as if students came into a hospital and received the same medicine and the same fifty-minute examinations from doctors and nurses who followed the same script regardless of the ailment and regardless of the particular specialty and previous training of the medical professionals.
The United States has roughly 5 million medical professionals but only 624,000 doctors who care for patients (Agency for Healthcare Research and Quality 2010). At its best, the medical system leverages each of those 5 million professionals to do what they can uniquely do best, with the role of an intake nurse different from that of a nurse practitioner, and different still from the X-ray technician, the medical resident, and the attending physician. Surely education could learn something from this differentiated approach.
Right now there are approximately 3.5 million full-time teachers employed to teach about 50 million U.S. students enrolled in about 100,000 K–12 schools (Hess 2010). There are another 2.5 million public school employees, ranging from special education paraprofessionals, to lunch monitors, librarians, secretaries, principals, custodians, and administrators. Whereas in the 1950s the ratio was one teacher for every twenty-eight students, today, in part due to growing numbers of special-education students, it is one to fifteen, and in urban districts it's one teacher for every twelve students (Scafidi 2012).
The sheer volume of teachers creates real problems for professionalization of the craft, as Rick Hess of the American Enterprise Institute, among others, have described. Even with modest rates of turnover, schools across the nation need to hire 280,000 new teachers per year, many more than the 120,000 full-time registered nurses hired each year, or the 26,000 new lawyers (Rampell 2011). As Hess (2009) notes, hiring 280,000 excellent teachers every year when there are only 1.5 million college graduates per year – and just 500,000 from competitive colleges – is an impossible task. A lot of people coming out of college don't want to be teachers, and yet we are trying to recruit almost one in five recent college graduates year after year. Imagine if we had slightly fewer teachers and paid them better and supported them with hundreds of thousands of teaching fellows, many of them training to become teachers but others taking a year or two to contribute to a local school before going on to careers in business or science or the arts. Most teaching fellows would be right out of college, but some might be older professionals transitioning to a new career in education.1 This more flexible talent model would provide more continuity with better-supported master teachers staying longer, while also infusing schools with fresh energy and additional talented and caring adults.
A model in which there were varying levels of teachers in a school would support educators at every level of experience, increase efficiency, and allow for more differentiation of student learning. Master teachers who had demonstrated excellent teaching over a sustained period of time could earn 50 percent more than typical teachers today and could teach one or two fewer classes per semester so they had time to coach their younger peers. Core teachers might have a similar teaching load to teachers today but would receive help from a teaching fellow, off-loading work such as grading of homework and tests, supervising student practice sessions, and management of field trips. This would allow core teachers to put more time into the development of great lesson plans.
Teaching fellows and volunteer citizen teachers could support the master and core teachers while also extending the learning day, providing more time for academic practice, more time for personalized learning (through online programs such as Khan Academy or software-based learning), and significantly more time for students to make and do things with real professionals. Together, this American Dream team of talented educators could build academic and social skills while also helping students discover the realworld applications of school-based knowledge.
I was ready for a change and I was looking for leadership opportunities beyond the classroom. Also, I personally wasn't able to sustain the intensity at which I was working for that number of hours in a day. Since I was coming to Orchard Gardens at the start of the turnaround, the work was still intense and I was working just as hard that first year, but the difference was that the work with students ran until about 2:20 and then Citizen Schools took over and I could use that afternoon time to work with my colleagues. [Having a high-quality partner extend the day for students while teachers prepare the next day's lesson with colleagues] means that we have more time to create better outcomes for kids and it makes the profession of teaching more sustainable.
In some respects this multitiered approach would look like the Isaac Newton Expanded Learning Time Middle School in East Harlem, which is located in the same building where my mom taught freshman English more than forty years ago. After many years of disappointing performance, Principal Lisa Nelson adopted ELT in 2011-2012 for all of the school's sixth graders and saw proficiency jump by 26 percentage points in math and 17 percentage points in English. Nelson, a veteran administrator, also saw a new spirit in her school. Her teachers and her leadership team felt buoyed by the energy of the Citizen Schools second shift, and she increasingly turned to Citizen Schools campus director Seth Miran as a trusted partner. Her school was infused with artists and engineers and financial professionals. My mom even came back to her old school building and taught an apprenticeship in organic farming and said she learned a few new teaching tricks she wished she'd had decades earlier.
Isaac Newton is now in the process of expanding ELT to all students in sixth through eighth grades. As part of this year's plan, Principal Nelson has asked her Citizen Schools teaching fellows to take the lead on interim assessments, including the administration of "exit tickets," which are two- to three-question assessments to check for understanding at the end of a single lesson. Teaching fellows will score the various interim assessments, load the data onto a spreadsheet, and conduct initial analysis that they can then share with Citizen Schools and school-day colleagues. The core teachers will have more time to focus on instruction and lesson planning and other high-value activities.
In many ways American education overall is headed in a positive direction. Despite the challenges our nation's schools face, average college graduation and high school graduation rates are going up, math scores are improving, and we now have hundreds – maybe even thousands – of schools delivering excellent results for low-income students. More outstanding college graduates are choosing to teach. We are moving toward a voluntarily adopted national Common Core curriculum that focuses more on higher-order thinking skills rather than regurgitation of memorized facts. And tests are about to become better, assessing writing and scientific thinking, not just the ability to guess correct answers on a fill-in-the-bubble test. The challenge for America is that while our schools are improving, schools around the world are improving faster. And the challenge for low-income American students is that while they are learning more – and their parents and their teachers are working harder – they are falling relatively further behind, left in the wake of a tsunami of privatized extra learning opportunities that benefit their upper-middle-class peers.
As I look today over a troubled public education landscape – a landscape where innovation and personalized learning is growing rapidly, but so is inequality – I yearn for the chance to rebuild our national sense of shared public purpose. Public schools were intended to knit together a new country, giving children of immigrants and of business owners the same chance at an excellent education. Today public schools and their teachers feel under siege. Some of that is deserved, a consequence of resistance to fair-minded change and higher standards. But surely much of the acrimony is undeserved, driven in part by the lack of connection and therefore lack of empathy between upper- and lower-income parents, between business leaders and teachers, and between all of us as American citizens.
Gandhi said that we must be the change we want to see in the world. If we want better public schools, we can't wait for some new curriculum or management plan or market mechanism. We need to roll up our sleeves and make them better. We need to step into schools with minimal judgment and as much curiosity and energy as we can muster. That's how to change the opportunity equation.
1. For more information on these types of programs see: EnCorps and Encore Fellowships.
Agency for Healthcare Research and Quality. 2010. "The Number of Practicing Primary Care Physicians in the United States." Fact sheet.
Hess, F. M. 2010. The Same Thing Over and Over: How School Reformers Get Stuck in Yesterday's Ideas. Cambridge, MA: Harvard University Press.
Ronfeldt, M., S. Loeb, and J. Wyckoff. 2013. "How Teacher Turnover Harms Student Achievement," American Educational Research Journal 50, no. 1:4–36.
Scafidi, B. 2012. The School Staffing Surge: Decades of Employment Growth in America's Public Schools. Indianapolis, IN: Friedman Foundation for Educational Choice.
Weingarten, R. 2011. "Evidence Matters," New York Times (April 23).


text:
Q: Why my leantween animation works in Unity editor but not on my Android device I have created a multi-player game. After the game gets over I am loading the game over scene.The leantween animation works perfectly fine in the Unity editor but when it comes to my android device it doesn't work only. I really can't understand why.
Here is my code
    public class GameOverManagerMP : MonoBehaviourPunCallbacks
    {
        // Start is called before the first frame update

        [SerializeField]private GameObject GameOverImage;
        [SerializeField]private GameObject Mylife;
        [SerializeField]private GameObject OpponentLife;
        [SerializeField]private GameObject Result;
        [SerializeField]private GameObject NetworkMessage;
        [SerializeField]private GameObject HomeButton;
        [SerializeField]private GameObject ShareButton;

        private float time = 0.9f;

        private void Awake()
        {
            Mylife.GetComponent<Text>().text = "My life : " + MultiPlayerScoreManager.instance.MyLifeCounter.ToString();
            OpponentLife.GetComponent<Text>().text = "Opponent life : " + MultiPlayerScoreManager.instance.OpponentLifeCounter.ToString();
            NetworkMessage.GetComponent<Text>().text = MultiPlayerScoreManager.instance.NetworkDisconnectedMessage;
            Result.GetComponent<Text>().text = MultiPlayerScoreManager.instance.FinalResult;
        }

        // public static Action DisconnectFromPhotonNetwork = delegate { };
        void Start()
        {
            SFXManager.PlaySound("whoosh");
            MoveGameOverElements();
        }

        private void MoveGameOverElements()
        {
 Debug.Log("Game Over Move Elements.................");
           GameOverImage.transform.LeanMoveLocal(new Vector2(0, 689f), time).setEaseOutQuad();
            Mylife.GetComponent<Text>().transform.LeanMoveLocal(new Vector2(-178f, 366f), time).setEaseOutQuad();
            OpponentLife.transform.LeanMoveLocal(new Vector2(-423f, 272f), time).setEaseOutQuad();
            LeanTween.scale(Result, Vector3.zero, 0f);
            LeanTween.scale(Result, new Vector3(1, 1, 1), 0.3f).setEase(LeanTweenType.easeInCubic);
            NetworkMessage.transform.LeanMoveLocal(new Vector2(-178f, -216f), time).setEaseOutQuad();
            HomeButton.transform.LeanMoveLocal(new Vector2(-216f, -609f), time).setEaseOutQuad();
            ShareButton.transform.LeanMoveLocal(new Vector2(157f, -609f), time).setEaseOutQuad();
        }
    }

The result text only has been given the scale 0 to scale 1 , a pop out like animation. I even commented the line where Time.timeScale=0; after the game got over in the previous scene, but there is no use as such. All the other elements either move to the left, right,top or bottom.
This is the screenshot of my Unity editor while it is not in Play mode :

Here is the screenshot of my Unity editor in Play mode:

Screenshot of the mobile(android) device. You can see in the bottom a little of the button is there on the screen
My aim to bring a fluid like animation into play when the game gets over

redpajama_set_name: RedPajamaStackExchange


text:
Head Coach: Patrick Gildea
Patrick has been coaching at West High School since 2011. He graduated from Tennessee where he lettered in track and cross country. He competed professionally representing the US on two occasions at the world championships in cross country and the half-marathon distance. He also holds a graduate degree from Saint Francis University. Patrick was named the 2016 KIL Women's Cross Country Coach of The Year.
Graduate Assistant Coach: Khadija Nisar
Khadija is a graduate student at Tennessee studying secondary education. She is an 8th grade social studies intern at Gresham Middle School. Khadija ran track and cross country for four years at Oglethorpe in Georgia. She coached at Atlanta International School during her senior year. She ran track and cross country at Germantown High School in Memphis.
Assistant Coach/YoungLife Leader: Marah Barnhart
Marah is an freshman nursing student at Tennessee. She ran competitively for Houston High School in Memphis. During her time at Houston she helped her team win two TSSAA titles in cross country. Marah is one six children. She is a YoungLife leader and involved in RUF at UT. She enjoys traveling, frisbee and running.
Time/Result
09/03/17 West Cross Country Meet Victor Ashe Park TBD
09/09/17 Cherokee Invitational To Be Determined TBD
09/16/17 Trinity/Valkyrie Classic EP Sawyer State Park TBD
09/23/17 Bristol Cross Country Steele Creek Park TBD
10/07/17 KIL Cross Country Meet Sequoyah Park TBD
10/26/17 Region 2 Championship Victor Ashe Park TBD
11/04/17 TSSAA State Championship Percy Warner Park TBD
12/02/17 Nike Cross Nationals Glendover Golf Course TBD
12/09/17 Footlocker National Championships Balboa Park TBD

redpajama_set_name: RedPajamaCommonCrawl


text:
Home Tags Leaks
Tag: leaks
Leaked Memo Shows Trump PR Team Desperately Trying To Sway Puerto...
Andrew Simpson - October 1, 2017
On Sunday morning, after what must have felt like the longest 11 days in Puerto Rican history, the inhabitants of the disaster-stricken island finally...
White House Leakers Leak Memo On Trump Administration's New Anti-Leak Program
thecitizeNY - September 14, 2017
The Trump administration has launched a broad new anti-leak program via a memorandum from National Security Advisor H.R. McMaster. The memo was leaked. Oh, the...
Jeff Sessions Is Going After The Press For Reporting On Leaks...
Matt Osborne - August 4, 2017
During a press conference today, Attorney General Jeff Sessions said that his Department of Justice is cracking down on leakers and reconsidering its rules...
After Leaked Transcripts Today, Trump's Old Tweet Comes Back At Him...
Conover - August 3, 2017
In early February, the newly sworn in fake news president tweeted, "Thank you to Prime Minister of Australia for telling the truth about our...
Funny Chit
New WH Talking Head Promises 'Drastic Action' On Leaks — Will...
Andrew Simpson - July 23, 2017
Anthony Scaramucci, that guy you know just got a job with Trump but can't remember which because all you can think of is a...
Sean Spicer Uses Alt-Facts To Falsely Claim A Fox News Reporter's...
Conover - March 8, 2017
White House press secretary Sean Spicer said on Wednesday at the daily press briefing that a Fox News reporter had his phones tapped while...
Speaking Of Leaks: 17 Top White House Officials Betray Trump To...
The Trump White House is completely out of control. Not just because Trump's fury is constantly at hand. His staff is clearly not that...
Sean Spicer Asks Staffers To Hand Over Their Phones To Find...
Conover - February 26, 2017
White House press secretary Sean Spicer is totally losing his shit over leaks which he thinks is coming from his own staff. Or not....
Emo Trump Laments 'Fake News' Media Was 'Very Unfair' To Mike...
Elisabeth Parker - February 15, 2017
A very emo Donald Trump lamented what he called the "fake news" media's "very unfair" treatment of Michael Flynn on Wednesday. In a press conference aired on...
Leaked RNC Speech Shows Trump Camp Compromised From Within
Matt Osborne - July 22, 2016
During this week's Republican National Convention, Donald Trump and his many of his speakers have made a great deal of noise about Hillary Clinton's...


Free Christmas Letter Templates Microsoft Word free christmas letter templates microsoft word christmas letter templates ideas. free christmas letter templates microsoft word christmas letter template for ms word download print templates. free christmas letter templates microsoft word printable christmas letter paper microsoft word template printable. Free Christmas Letter Templates Microsoft Word free christmas letter templates microsoft word christmas letter templates microsoft word free webpixer throughout templates. free christmas letter templates microsoft word microsoft word christmas letter templates insaatmcpgroupco download. free christmas letter templates microsoft word 13 christmas letter templates word apple pages google docs download. Free Christmas Letter Templates Microsoft Word free christmas letter templates microsoft word free christmas letter template insaatmcpgroupco templates.
Free Christmas Letter Templates Microsoft Word free christmas letter templates microsoft word christmas letter template for ms word download print templates. free christmas letter templates microsoft word printable christmas letter paper microsoft word template printable. free christmas letter templates microsoft word christmas letter templates microsoft word free webpixer throughout templates. free christmas letter templates microsoft word microsoft word christmas letter templates insaatmcpgroupco download. free christmas letter templates microsoft word 13 christmas letter templates word apple pages google docs download.


Tomorrow, I'm traveling as far away from my home as possible.
I'm traveling 18.000 km and 11 timezones away, to New Zealand. And I am doing this with nothing more than my 38 l backpack that I use as hand luggage. I have noticed that people often are surprised of how little I bring when I travel. But I like to keep it simple and minimalistic. Nowadays, most people(me included) have too much stuff. And even though I am only gone for 5 weeks, I would bring the same bag with the same things if I where to travel for an indefinite time.
I even feel like I am bringing more than I need right now.
First of all, it is so convenient. I don't have to worry about my luggage getting lost on the way, and when the plane lands, I can just take my backpack and walk away and not have to wait for my bag to come.
Another reason is that I want to live a more simple life, and not buy and own more stuff than what I actually need. I don't like how we are taught that we always need more stuff, or change in perfectly working stuff for a newer model just to have the latest of everything.
But the biggest reason is way more simple than that. I don't want to carry around a large and heavy backpack everywhere. And I don't need more than what I will bring.
Hello! I am planning to travel alone this summer. Can you give me any tips? I have traveled a lot before, but only in a minimum 2 person setting. Before, I could afford to take the tent and sleep on the beach or in camping sites or, if we were in the middle of nowhere, there. The thing is, as I enjoyed it a lot, doing it alone raises me questions… How do you deal with accommodation? Couchsurfing, hostels?
Exciting! I love sleeping in tents too, but I have not tried doing it alone. I would not have trouble doing it on locations where others are camping too, but I'm not sure I would be brave enough to do it everywhere.
Yes, I couchsurf or stay at hostels when I travel. It's about 50/50.
Sometimes I stay at hotels, but that is a luxury I sure could give up easily.
Where do you plan to travel this summer? In some places, the accommodation of hostels or bungalows are extremely cheap.
Can I ask please how much did this weigh?
love traveling , couchsurfing , having a couchsurfer here in two days … when the ski season is over i hope i will be able to go travel again … do you know nomads ?
I plan to change to the cup, but I want to try it at home first and didn't have time to do it before the trip.
Hi Jess! This ended up being around 8-9 kgs.. Will probably dropp some things off along the way and get a smaller and lighter packpack for future travels .
Well, we all travel differently, and what and how much we bring obviously differs depending on different destinations or types of travels. Have an awesome time in Oz!
As a girl living in Oz I can tell you that if you are coming here to holiday for a week or a year you dont need to bring much at all! If you are coming in summer all you will need is a bikini! Most important items to bring are your travel docs and camera then bring everything else when you get here! Our op shops (charity shops) often have some pretty amazing finds and then you could donate your clothes back to help someone in need before you leave.
I agree Emma! I'm always trying to downsize my packings. People usually live where you're going, so all you need is there!
Tänkte för första gången på min 3e långresa jorden runt resa bara med handbagage. Tack för inspirationen jag fått på din blogg 🙂 Får se hur det går.
I realised when I traveled to San Francisco and Northern California this summer for 3 weeks – that I had brought way too much stuff, even though my bag was only 11 kgs (with gifts included). I ended up using only half of my stuff since I had to possibility to do my laundry 🙂 I guess the problem is if you wanna do some shopping abroad – how do you deal with that?


text:
Grainger's Woodrow sets up own BTR business
By Helen Crane2018-10-08T10:56:00
Mark Woodrow has left Grainger to set up a new build-to-rent development and advisory company called BTR Partners.
The company will act as an originator and developer of BTR opportunities, as well as providing development management and consultancy services to investors, developers and public sector organisations.
This content is only available to registered users
You must be logged in to continue
Would you like to read more?
Register for free to finish this article
Registration includes the following benefits:
Access up to four FREE articles per month
Breaking news, comment and analysis from industry experts as it happens
Choose from our portfolio of email newsletters
To access this article REGISTER NOW
Four articles not enough? SUBSCRIBE for unlimited access to over 100 weekly articles and our comprehensive archive. For as little as £5 per week.
Registered users and subscribers SIGN IN here to continue


As our Business Development Coordinator, Bruce has been tapped to track the office leasing market in the Portland area. While growing up in Utah, Bruce knew early on that he wanted to make Portland his home, so he attended the University of Portland and graduated with a degree in communications and philosophy. Prior to Apex, Bruce was a client success manager at one of the fastest growing companies in Portland which shaped his approach of always putting the client first. As a result, he aims to be a true resource and partner, understanding that the right office space is critical to achieving financial and cultural goals.


text:
California/
Where is North Glendale
Where is North Glendale, CA?
Location of North Glendale on a map.
North Glendale is a city found in California, The United States Of America. It is located 34.16 latitude and -118.26 longitude and it is situated at elevation 168 meters above sea level.
North Glendale has a population of 203,201 making it the 17th biggest city in California. It operates on the PDT time zone, which means that it follows the same time zone as Los Angeles.
Time Zone PDT
Longitude -118.264520
North-glendale has a population of around 196984, of which 94216 (47%) are male and 102768 (52%) are female. The average age of the inhabitants of North-glendale is 40.98, meaning that the average person is above the national median age of 37. For every male, there are approximately 1.09 females, meaning that the population is relatively evenly distributed between males and female(s).
Of North-glendale's 196984 residents, around 190562 (96.70%) identify as having a single race. The majority of the population is white, which consists of 72.70% of the population. Of the remaining population, 2631 are black/African Americans (1.30%), 806 are native Americans (0.40%), 33164 are asians (16.00%), 116 are pacific islanders (0.10%), 10557 are other (5.40%).
The median income of households in North-glendale is $52574.00, meaning that most of the households are above the poverty threshold for families of three. Of the total population, 4.80% of households reported an annual income of less than $10,000.
North Glendale, CA Zipcodes
The city of North Glendale has 14 zipcodes recognized by the United States Census Bureau: 90039, 91011, 91020, 91046, 91201, 91202, 91203, 91204, 91205, 91206, 91207, 91208, 91210, 91214.
Most Popular Cities in California