text:
// Helpers for op implementations
//
// This file declares simple helper routines to make it easier to write metadata
// function and dispatch function for a op. This is intended to be small and
// simple things and is nearly header-only.

// TODO(fishx): Split this file into metadata_utils.h and dispatch_utils.h.

#ifndef TFRT_CORE_RUNTIME_OP_UTILS_H_
#define TFRT_CORE_RUNTIME_OP_UTILS_H_

#include <tuple>
#include <type_traits>

#include "llvm/ADT/FunctionExtras.h"
#include "llvm/Support/Error.h"
#include "tfrt/core_runtime/op_args.h"
#include "tfrt/core_runtime/op_attrs.h"
#include "tfrt/host_context/async_value_ref.h"
#include "tfrt/host_context/chain.h"
#include "tfrt/host_context/diagnostic.h"
#include "tfrt/host_context/kernel_frame.h"
#include "tfrt/host_context/kernel_utils.h"
#include "tfrt/host_context/location.h"
#include "tfrt/support/rc_array.h"
#include "tfrt/tensor/tensor_metadata.h"

namespace tfrt {
class Tensor;
struct TensorMetadata;

//===----------------------------------------------------------------------===//
// Registration helpers used to make metadata function easier to define.
//===----------------------------------------------------------------------===//

// TFRT_METADATA is a macro that makes defining metadata function more
// straightforward. Example:
//
//   RCReference<AsyncValue> AddMetadataFn(const TensorMetadata& a,
//                                         const TensorMetadata& b,
//                                         TensorMetadata* c,
//                                         const ExecutionContext& exec_ctx) {
//     // Check argument metadata.
//     if (error) return EmitErrorAsync(exec_ctx, "error");
//     *result = TensorMetadata(a.dtype, a.shape);
//     return {};
//   }
//
// Example for metadata function that needs OpAttrs:
//
//   void ExampleMetadataFn(const TensorMetadata argument,
//                          const OpAttrsRef& attrs,
//                          TensorMetadata* result,
//                          const ExecutionContext& exec_ctx) { ... }
//
#define TFRT_METADATA(...) \
  ::tfrt::MetadataFnImpl<decltype(&__VA_ARGS__), &__VA_ARGS__>::Invoke

//===----------------------------------------------------------------------===//
// Registration helpers used to make cpu dispatch function easier to define.
//===----------------------------------------------------------------------===//

// TFRT_CPU_OP is a macro that makes defining dispatch
// function more straightforward. Example:
//
//   void AddDispatchFn(const HostTensor& a,
//                      const HostTensor& b,
//                      const TensorMetadata& c_md,
//                      HostTensor* c,
//                      const ExecutionContext& exec_ctx) { ... }
//
// Example for dispatch function that needs OpAttrs:
//
//   void ExampleDispatchFn(const HostTensor& a,
//                          const HostTensor& b,
//                          const OpAttrsRef& attrs,
//                          const TensorMetadata& c_md,
//                          HostTensor* c,
//                          const ExecutionContext& exec_ctx) { ... }
//
// TODO(fishx): Move it to backends/cpu.
#define TFRT_CPU_OP(...)                                      \
  ::tfrt::DispatchFnImpl<HostContext, decltype(&__VA_ARGS__), \
                         &__VA_ARGS__>::Invoke

// This class is an implementation detail of TFRT_METADATA.
template <typename F, F f>
struct MetadataFnImpl;

template <typename ReturnT, typename... Args, ReturnT (*impl_fn)(Args...)>
struct MetadataFnImpl<ReturnT (*)(Args...), impl_fn> {
  static RCReference<AsyncValue> Invoke(
      const ExecutionContext& exec_ctx, ArrayRef<TensorMetadata> arguments,
      const OpAttrsRef& attrs, MutableArrayRef<TensorMetadata> results) {
    return HandleReturn(
        MetadataFnCallHelper<Args..., void>::template Invoke<0, 0, false>(
            arguments, attrs, results, exec_ctx),
        results, exec_ctx);
  }

 private:
  static RCReference<AsyncValue> HandleReturn(
      RCReference<AsyncValue> v, MutableArrayRef<TensorMetadata> results,
      const ExecutionContext& exec_ctx) {
    return v;
  }

  template <typename T>
  static RCReference<AsyncValue> HandleReturn(
      llvm::Expected<T>&& v, MutableArrayRef<TensorMetadata> results,
      const ExecutionContext& exec_ctx) {
    if (v) {
      return HandleReturn(std::move(*v), results, exec_ctx);
    } else {
      return EmitErrorAsync(
          exec_ctx, absl::InvalidArgumentError(toString(v.takeError())));
    }
  }

  static RCReference<AsyncValue> HandleReturn(
      TensorMetadata&& v, MutableArrayRef<TensorMetadata> results,
      const ExecutionContext& exec_ctx) {
    assert(results.size() == 1 && "Incorrect number of return values");
    results[0] = std::move(v);
    return {};
  }

  template <typename... T>
  static RCReference<AsyncValue> HandleReturn(
      std::tuple<T...>&& t, MutableArrayRef<TensorMetadata> results,
      const ExecutionContext& exec_ctx) {
    assert(results.size() == sizeof...(T) &&
           "Incorrect number of return values");
    EmplaceTupleResult(results, std::move(t),
                       std::make_index_sequence<sizeof...(T)>{});
    return {};
  }

  // Helper function for storing multiple return values in std::tuple<> in the
  // results ArrayRef.
  template <typename TupleT, size_t... I>
  static void EmplaceTupleResult(MutableArrayRef<TensorMetadata> results,
                                 TupleT&& result, std::index_sequence<I...>) {
    // Use braced-init-list to retrieve the results in the tuple in sequence.
    std::ignore = std::initializer_list<int>{
        (results[I] = std::get<I>(std::forward<TupleT>(result)), 0)...};
  }

  // Helper that introspects the MetadataFn's arguments to derive the signature
  // and pass arguments, attributes, results and location to impl_fn. Works by
  // recursively unpacking the MetadataFn's arguments.
  template <typename... RemainingArgs>
  struct MetadataFnCallHelper;

  // Specialization for passing a TensorMetadata argument.
  template <typename... RemainingArgs>
  struct MetadataFnCallHelper<const TensorMetadata&, RemainingArgs...> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... pargs) {
      static_assert(arg_idx != -1,
                    "Do not place argument TensorMetadata after OptionalOpArg "
                    "or VariadicOpArg");
      static_assert(!has_attrs,
                    "Do not place argument TensorMetadata after OpAttrsRef");
      static_assert(
          result_idx == 0,
          "Do not place argument TensorMetadata after result TensorMetadata");
      assert(arg_idx < arguments.size());
      const TensorMetadata& argument = arguments[arg_idx];
      return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx + 1, result_idx, has_attrs>(arguments, attrs, results,
                                              exec_ctx, pargs..., argument);
    }
  };

  // Specialization for passing an optional argument.
  template <typename Head, typename... RemainingArgs>
  struct MetadataFnCallHelper<OptionalOpArg<Head>, RemainingArgs...> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... pargs) {
      static_assert(arg_idx != -1,
                    "Do not use more than one OptionalOpArg, or more than one "
                    "VariadicOpArg, or mix OptionalOpArg and VariadicOpArg");
      static_assert(
          !has_attrs,
          "Do not place optional argument TensorMetadata after OpAttrsRef");
      static_assert(result_idx == 0,
                    "Do not place optional argument TensorMetadata after "
                    "result TensorMetadata");
      assert(arg_idx == arguments.size() - 1 || arg_idx == arguments.size());
      if (arg_idx < arguments.size()) {
        const TensorMetadata& argument = arguments[arg_idx];
        return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
            -1, result_idx, has_attrs>(arguments, attrs, results, exec_ctx,
                                       pargs..., &argument);
      } else {
        return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
            -1, result_idx, has_attrs>(arguments, attrs, results, exec_ctx,
                                       pargs..., OptionalOpArg<Head>());
      }
    }
  };

  // Specialization for passing a variadic argument.
  template <typename Head, typename... RemainingArgs>
  struct MetadataFnCallHelper<VariadicOpArg<Head>, RemainingArgs...> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... pargs) {
      static_assert(arg_idx != -1,
                    "Do not use more than one OptionalOpArg, or more than one "
                    "VariadicOpArg, or mix OptionalOpArg and VariadicOpArg");
      static_assert(
          !has_attrs,
          "Do not place optional argument TensorMetadata after OpAttrsRef");
      static_assert(result_idx == 0,
                    "Do not place optional argument TensorMetadata after "
                    "result TensorMetadata");
      assert(arg_idx <= arguments.size());
      auto var_args = arguments.drop_front(arg_idx);
      return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
          -1, result_idx, has_attrs>(arguments, attrs, results, exec_ctx,
                                     pargs...,
                                     VariadicOpArg<TensorMetadata>(var_args));
    }
  };

  // Specialization for passing an OpAttrsRef.
  template <typename... RemainingArgs>
  struct MetadataFnCallHelper<const OpAttrsRef&, RemainingArgs...> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... pargs) {
      static_assert(!has_attrs, "Do not place more than one OpAttrsRef");
      static_assert(
          result_idx == 0,
          "Do not place argument OpAttrsRef after result TensorMetadata");
      return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, true>(arguments, attrs, results, exec_ctx,
                                     pargs..., attrs);
    }
  };

  // Specialization for passing a TensorMetadata result.
  template <typename... RemainingArgs>
  struct MetadataFnCallHelper<TensorMetadata*, RemainingArgs...> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... pargs) {
      assert(result_idx < results.size());
      TensorMetadata* result = &results[result_idx];
      return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx + 1, has_attrs>(arguments, attrs, results,
                                              exec_ctx, pargs..., result);
    }
  };

  // Specialization for passing a const ExecutionContext&.
  template <typename... RemainingArgs>
  struct MetadataFnCallHelper<const ExecutionContext&, RemainingArgs...> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... pargs) {
      return MetadataFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, has_attrs>(arguments, attrs, results, exec_ctx,
                                          pargs..., exec_ctx);
    }
  };

  // Base case: No arguments left.
  // The trailing template argument works around around the restriction of GCC
  // not being fully C++14 compliant and not allowing fully specialized
  // templates in class scope.
  template <typename T>
  struct MetadataFnCallHelper<T> {
    template <int arg_idx, int result_idx, bool has_attrs,
              typename... PreviousArgs>
    static ReturnT Invoke(ArrayRef<TensorMetadata> arguments,
                          const OpAttrsRef& attrs,
                          MutableArrayRef<TensorMetadata> results,
                          const ExecutionContext& exec_ctx,
                          const PreviousArgs&... args) {
      assert((arg_idx == arguments.size() || arg_idx == -1) &&
             "Extra arguments passed to metadata function.");
      assert((result_idx == results.size() || result_idx == 0) &&
             "Extra results passed to metadata function.");
      return impl_fn(args...);
    }
  };
};

// This class is an implementation detail of TFRT_CPU_OP.
template <typename DeviceContext, typename F, F f>
struct DispatchFnImpl;

template <typename DeviceContext, typename Return, typename... Args,
          Return (*impl_fn)(Args...)>
struct DispatchFnImpl<DeviceContext, Return (*)(Args...), impl_fn> {
  // Only add DeviceContext* in the dispatch function if DeviceContext is not
  // HostContext.
  template <typename T = DeviceContext,
            std::enable_if_t<!std::is_same<T, HostContext>::value, int> = 0>
  static void Invoke(const ExecutionContext& exec_ctx, DeviceContext* ctx,
                     ArrayRef<AsyncValue*> arguments, const OpAttrsRef& attrs,
                     ArrayRef<TensorMetadata> result_mds,
                     MutableArrayRef<RCReference<AsyncValue>> results,
                     AsyncValueRef<Chain>* chain) {
    DispatchFnCallHelper<Args..., void>::template Invoke<0, 0, 0, false, false>(
        ctx, arguments, attrs, result_mds, results, chain, exec_ctx);
  }

  // If DeviceContext is HostContext, avoid adding HostContext as an
  // argument for the dispatch function, as HostContext is already available in
  // ExecutionContext.
  template <typename T = DeviceContext,
            std::enable_if_t<std::is_same<T, HostContext>::value, int> = 0>
  static void Invoke(const ExecutionContext& exec_ctx,
                     ArrayRef<AsyncValue*> arguments, const OpAttrsRef& attrs,
                     ArrayRef<TensorMetadata> result_mds,
                     MutableArrayRef<RCReference<AsyncValue>> results,
                     AsyncValueRef<Chain>* chain) {
    DispatchFnCallHelper<Args..., void>::template Invoke<0, 0, 0, false, false>(
        exec_ctx.host(), arguments, attrs, result_mds, results, chain,
        exec_ctx);
  }

 protected:
  // The return value is AsyncValueRef<T>.
  template <int result_idx, bool has_chain, typename T>
  struct DispatchReturnHelper {
    static void Invoke(MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx, const Args&... args) {
      HandleReturn<result_idx, has_chain>(results, chain, exec_ctx,
                                          impl_fn(args...));
    }
  };

  // The return value is void.
  template <int result_idx, bool has_chain>
  struct DispatchReturnHelper<result_idx, has_chain, void> {
    static void Invoke(MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx, const Args&... args) {
      assert(result_idx == results.size() &&
             "Extra results passed to dispatch function.");
      impl_fn(args...);
    }
  };

  // For ops functions that return T.
  template <int result_idx, bool has_chain, typename T>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx, T&& t) {
    static_assert(result_idx == 0,
                  "Do not both have result argument and return result");
    assert(results.size() == 1 && "Incorrect number of return value");
    results[0] = MakeAvailableAsyncValueRef<T>(std::forward<T>(t));
  }

  // For ops functions that return AsyncValueRef<Chain>.
  template <int result_idx, bool has_chain>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx,
                           AsyncValueRef<Chain>&& t) {
    static_assert(!has_chain,
                  "Do not both have chain argument and return chain");
    assert(result_idx == results.size() &&
           "Extra results passed to dispatch function.");
    *chain = std::move(t);
  }

  // For ops functions that return AsyncValueRef<T>.
  template <int result_idx, bool has_chain, typename T>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx,
                           AsyncValueRef<T> t) {
    static_assert(result_idx == 0,
                  "Do not both have result argument and return result");
    assert(results.size() == 1 && "Incorrect number of return value");
    results[0] = std::move(t);
  }

  // For ops functions that return RCReference<AsyncValue>.
  template <int result_idx, bool has_chain>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx,
                           RCReference<AsyncValue> t) {
    static_assert(result_idx == 0,
                  "Do not both have result argument and return result");
    assert(results.size() == 1 && "Incorrect number of return value");
    // Add location information to error result if necessary.
    t->AndThen([t = t.get(), exec_ctx] {
      if (t->IsError()) {
        exec_ctx.host()->EmitError(
            DecodedDiagnostic(exec_ctx.location().Decode(), t->GetError()));
      }
    });
    results[0] = std::move(t);
  }

  // For ops functions that return std::array<AsyncValueRef<T>, N>.
  template <int result_idx, bool has_chain, typename T, size_t N>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx,
                           std::array<AsyncValueRef<T>, N> t) {
    static_assert(result_idx == 0,
                  "Do not both have result argument and return result");
    assert(results.size() == t.size() && "Incorrect number of return values");
    for (int i = 0, e = t.size(); i < e; ++i) {
      results[i] = t[i].ReleaseRCRef();
    }
  }

  // For ops functions that return Expected<T>.
  template <int result_idx, bool has_chain, typename T>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx, Expected<T>&& t) {
    static_assert(result_idx == 0,
                  "Do not both have result argument and return result");
    if (t) {
      HandleReturn<result_idx, has_chain>(results, chain, exec_ctx,
                                          std::move(*t));
    } else {
      results[0] = EmitErrorAsync(exec_ctx, toString(t.takeError()));
      for (size_t i = 1, e = results.size(); i != e; ++i) {
        results[i] = results[0];
      }
    }
  }

  // For kernel functions that return std::tuple<>, store the results in order
  // as the output AsyncValues in the AsyncKernelFrame.
  template <int result_idx, bool has_chain, typename... T>
  static void HandleReturn(MutableArrayRef<RCReference<AsyncValue>> results,
                           AsyncValueRef<Chain>* chain,
                           const ExecutionContext& exec_ctx,
                           std::tuple<T...>&& t) {
    assert(results.size() == sizeof...(T) &&
           "Incorrect number of results passed to op.");
    EmplaceTupleResult(results, exec_ctx, std::move(t),
                       std::make_index_sequence<sizeof...(T)>{});
  }

  // Helper function for storing multiple return values in std::tuple<> as
  // output AsyncValue in AsyncKernelFrame.
  template <typename TupleT, size_t... I>
  static void EmplaceTupleResult(
      MutableArrayRef<RCReference<AsyncValue>> results,
      const ExecutionContext& exec_ctx, TupleT&& result,
      std::index_sequence<I...>) {
    // Use braced-init-list to retrieve the results in the tuple in sequence.
    std::ignore = std::initializer_list<int>{
        (results[I] =
             MakeAvailableAsyncValueRef<std::tuple_element_t<I, TupleT>>(
                 std::get<I>(std::forward<TupleT>(result))),
         0)...};
  }

  // Helper that introspects the DispatchFn's arguments to derive the signature
  // and pass arguments, attributes, results, out_chain and location to impl_fn.
  // Works by recursively unpacking the DispatchFn's arguments.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper;

  // Specialization for passing OpAttrsRef.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper<const OpAttrsRef&, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(!has_attrs, "Do not place more than one OpAttrsRef");
      static_assert(!has_chain, "Do not place argument OpAttrsRef after chain");
      static_assert(result_idx == 0,
                    "Do not place OpAttrsRef after result Tensor");
      static_assert(md_idx == 0,
                    "Do not place OpAttrsRef after result Metadata");
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, md_idx, true, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          attrs);
    }
  };

  // Specialization for passing a Metadata result.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper<const TensorMetadata&, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(result_idx == 0,
                    "Do not place result Metadata after result Tensor");
      static_assert(!has_chain, "Do not place result Metadata after chain");
      assert(md_idx < result_mds.size());
      const TensorMetadata& md = result_mds[md_idx];
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, md_idx + 1, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          md);
    }
  };

  // Specialization for passing a Tensor result.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper<RCReference<AsyncValue>*, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(!has_chain, "Do not place result Tensor after chain");
      assert(result_idx < results.size());
      RCReference<AsyncValue>* arg = &results[result_idx];
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx + 1, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          arg);
    }
  };

  // Specialization for passing out_chain.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper<AsyncValueRef<Chain>*, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(!has_chain, "Do not place more than one chain");
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, md_idx, has_attrs, true>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          chain);
    }
  };

  // Specialization for passing const ExecutionContext&.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper<const ExecutionContext&, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          exec_ctx);
    }
  };

  // Specialization for passing DeviceContext*.
  template <typename... RemainingArgs>
  struct DispatchFnCallHelper<DeviceContext*, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(!std::is_same<DeviceContext, HostContext>::value,
                    "Does not support host context");
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx, result_idx, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          ctx);
    }
  };

  // Specialization for passing a Tensor pointer argument.
  template <typename Head, typename... RemainingArgs>
  struct DispatchFnCallHelper<Head*, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(std::is_base_of<Tensor, Head>::value,
                    "Only support Tensor argument");
      static_assert(!has_chain, "Do not place argument Tensor after chain");
      static_assert(!has_attrs,
                    "Do not place argument Tensor after OpAttrsRef");
      static_assert(result_idx == 0,
                    "Do not place argument Tensor after result Tensor");
      static_assert(md_idx == 0,
                    "Do not place argument Tensor after result Metadata");
      assert(arg_idx < arguments.size());

      // The CPU device will implicitly convert argument for us in the future.
      Head& arg = arguments[arg_idx]->get<Head>();
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx + 1, result_idx, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          &arg);
    }
  };

  // Specialization for passing a const ref Tensor argument.
  template <typename Head, typename... RemainingArgs>
  struct DispatchFnCallHelper<const Head&, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(std::is_base_of<Tensor, Head>::value,
                    "Only support Tensor argument");
      static_assert(!has_chain, "Do not place argument Tensor after chain");
      static_assert(!has_attrs,
                    "Do not place argument Tensor after OpAttrsRef");
      static_assert(result_idx == 0,
                    "Do not place argument Tensor after result Tensor");
      static_assert(md_idx == 0,
                    "Do not place argument Tensor after result Metadata");
      assert(arg_idx < arguments.size());

      // The CPU device will implicitly convert argument for us in the future.
      Head& arg = arguments[arg_idx]->get<Head>();
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx + 1, result_idx, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          arg);
    }
  };

  // Specialization for passing an argument.
  template <typename Head, typename... RemainingArgs>
  struct DispatchFnCallHelper<Argument<Head>, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      static_assert(std::is_base_of<Tensor, Head>::value,
                    "Only support Tensor argument");
      static_assert(!has_chain, "Do not place argument Tensor after chain");
      static_assert(!has_attrs,
                    "Do not place argument Tensor after OpAttrsRef");
      static_assert(result_idx == 0,
                    "Do not place argument Tensor after result Tensor");
      static_assert(md_idx == 0,
                    "Do not place argument Tensor after result Metadata");
      assert(arg_idx < arguments.size());

      // The CPU device will implicitly convert argument for us in the future.
      Argument<Head> arg(arguments[arg_idx]);
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          arg_idx + 1, result_idx, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          arg);
    }
  };

  // Specialization for passing an optional ref Tensor argument.
  template <typename Head, typename... RemainingArgs>
  struct DispatchFnCallHelper<OptionalOpArg<Head>, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      // TODO(jingdong): Deduplicate static_assert checks across other template
      // specializations.
      static_assert(std::is_base_of<Tensor, Head>::value,
                    "Only support optional Tensor argument");
      static_assert(arg_idx != -1,
                    "Do not use more than one OptionalOpArg, or more than one "
                    "VariadicOpArg, or mix OptionalOpArg and VariadicOpArg");
      static_assert(!has_chain,
                    "Do not place optional Tensor argument after chain");
      static_assert(!has_attrs,
                    "Do not place optional Tensor argument after OpAttrsRef");
      static_assert(
          result_idx == 0,
          "Do not place optional Tensor argument after result Tensor");
      static_assert(
          md_idx == 0,
          "Do not place optional Tensor argument after result Metadata");

      assert(arg_idx == arguments.size() - 1 || arg_idx == arguments.size());
      if (arg_idx < arguments.size()) {
        // The GPU device will implicitly convert argument for us in the future.
        Head* arg = &arguments[arg_idx]->get<Head>();
        // TODO(b/146386166): Emit error instead of assert().
        assert(arg && "requires Tensor input");
        DispatchFnCallHelper<RemainingArgs...>::template Invoke<
            -1, result_idx, md_idx, has_attrs, has_chain>(
            ctx, arguments, attrs, result_mds, results, chain, exec_ctx,
            pargs..., arg);
      } else {
        DispatchFnCallHelper<RemainingArgs...>::template Invoke<
            -1, result_idx, md_idx, has_attrs, has_chain>(
            ctx, arguments, attrs, result_mds, results, chain, exec_ctx,
            pargs..., OptionalOpArg<Head>());
      }
    }
  };

  // Specialization for passing a variadic ref Tensor argument.
  template <typename Head, typename... RemainingArgs>
  struct DispatchFnCallHelper<RepeatedArguments<Head>, RemainingArgs...> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... pargs) {
      // TODO(jingdong): Deduplicate static_assert checks across other template
      // specializations.
      static_assert(std::is_base_of<Tensor, Head>::value,
                    "Only support optional Tensor argument");
      static_assert(arg_idx != -1,
                    "Do not use more than one OptionalOpArg, or more than one "
                    "VariadicOpArg, or mix OptionalOpArg and VariadicOpArg");
      static_assert(!has_chain,
                    "Do not place optional Tensor argument after chain");
      static_assert(!has_attrs,
                    "Do not place optional Tensor argument after OpAttrsRef");
      static_assert(
          result_idx == 0,
          "Do not place optional Tensor argument after result Tensor");
      static_assert(
          md_idx == 0,
          "Do not place optional Tensor argument after result Metadata");

      assert(arg_idx <= arguments.size());
      ArrayRef<AsyncValue*> var_tensor_args = arguments.drop_front(arg_idx);
      DispatchFnCallHelper<RemainingArgs...>::template Invoke<
          -1, result_idx, md_idx, has_attrs, has_chain>(
          ctx, arguments, attrs, result_mds, results, chain, exec_ctx, pargs...,
          RepeatedArguments<Head>(var_tensor_args));
    }
  };

  // Base case: No arguments left.
  // The trailing template argument works around around the restriction of GCC
  // not being fully C++14 compliant and not allowing fully specialized
  // templates in class scope.
  template <typename T>
  struct DispatchFnCallHelper<T> {
    template <int arg_idx, int result_idx, int md_idx, bool has_attrs,
              bool has_chain, typename... PreviousArgs>
    static void Invoke(DeviceContext* ctx, ArrayRef<AsyncValue*> arguments,
                       const OpAttrsRef& attrs,
                       ArrayRef<TensorMetadata> result_mds,
                       MutableArrayRef<RCReference<AsyncValue>> results,
                       AsyncValueRef<Chain>* chain,
                       const ExecutionContext& exec_ctx,
                       const PreviousArgs&... args) {
      // TODO(b/146386166): Emit error instead of assert().
      assert((arg_idx == arguments.size() || arg_idx == -1) &&
             "Extra arguments passed to dispatch function.");
      assert((md_idx == result_mds.size() || md_idx == 0) &&
             "Extra result Metadatas passed to dispatch function.");
      DispatchReturnHelper<result_idx, has_chain, Return>::Invoke(
          results, chain, exec_ctx, args...);
    }
  };
};
}  //  namespace tfrt
#endif  // TFRT_CORE_RUNTIME_OP_UTILS_H_


XplicitConcerts has uploaded video footage of TRIVIUM's May 10 performance at the Rise Above Fest in Bangor, Maine. Check it out below.
TRIVIUM last week parted ways with drummer Nick Augusto due to personal differences. TRIVIUM bassist Paolo Gregoletto stated about the split: "We all agreed that what started out great 'off stage' in the beginning over time began to fray. It became obvious that things were not going to work out in the long run.
"We did not want to reach the point where the differences between us became apparent on stage.
"Being in a band is privilege afforded to us by all of you, and as much as we owe you guys the best show we can possibly give you, we also realize that being out here has to be enjoyable enough for us to continue to do so."
Stepping in for Augusto on TRIVIUM's current dates is the band's drum tech, Mat Madiro.
TRIVIUM's new album, "Vengeance Falls", made Top 10 chart debuts in Japan, Australia, Germany and Austria as well as a Top 15 debut in Canada and a Top 25 debut in the United Kingdom. This marked the acclaimed metallers' second consecutive Top 15 debut in the U.S. and highest-career debuts around the globe — including a No. 2 debut in Japan.


text:
Channel swim training the wrong way – January to June 2020
Now, a lot of people already know that I'm going to swim the Channel in September 2021, so it's time for me to share my training progress.
At the end of 2018, the idea of swimming the Channel during a working holiday in 2021 appeared in my mind. It would be a fun and extraordinary thing for me to do, to make my working holiday special and unregrettable. Morever, at that time, there weren't any Hongkongers who had swum the Channel yet, if I got it across before anyone else I would make history and I would be proud. As Channel swimming isn't a thing that should be taken lightly, I dared not commit myself to that yet despite pilots normally take booking 2 to 3 years ahead. Instead, I wrote the following:
While for swimming, I have a very ambitious goal which I don't know if it is achievable or not – swim the channel in 2021, during a working holiday that year. In order to know if I am ready for that challenge, I would like to try the cold half (a 15 km open water race in Hong Kong in winter) in 2020, if I can complete it that means I am ready for that challenge. Therefore, I need to train a lot in 2019, eventually build up to 15 km without wetsuit by the end of the year.
Everything went well in 2019. I complete the race January this year, although it was not as cold as I expected. Initially I had a bit of self doubt after my race, but I got over it soon after taking a week's break:
However, judging from my feeling after the race, I really doubt if I should continue my plan or not. My plan was to sign up for a channel swimming spot in late 2021, and to do a 21 km lake race in Sweden, "Vidösternsimmet", in August 2020 with expected lake temperature 18°C, to further build up my distance combined with an orienteering trip to Poland. This race was an easy race, nothing was challenging. The water was warm (19 – 20°C) and the sea was calm most of the time. However, despite of that, my fatigue started to built up just after 7 km, and after 10 km, every km was a struggle for me, and it was only my mind keeping me going, counting every half km in the way from Round Island to the finish to end my suffering.
I found a good September 2021 slot with a CSA pilot after the race. I sent the deposit on 31st January, just 12 days after my race. Then I signed up Vidösternsimmet just a few days later. I made a training plan which consisted of 3 training blocks:
February 2020 – June 2020: I would do swim lessons with Chung Ho to correct my technique, and train for speed when the swimming pool was still cold enough. Starting from April, gradually shift my training focus from speed to distance such that I would be ready for 21 km by June in order to do Vidösternsimmet. As it was a lake race, the time I got would provide a good measure of what my ability was because there would be no current and tide, and I would use that time as a basis to estimate what was my sustainable speed over a long distance, and to plan my further training.
November 2020 – March 2021: I would leave my job at contract maturity in October. Then I would dedicate myself for my training. I would build up from the 21 km foundation done in the previous block. I would train in various environments like swimming in swells, currents and chops, at night, in cold weather, alongside a boat, etc., in order to get me ready for the Channel. I would do a rehearsal swim of about 30 km in February, when the sea temperature would be about 16 – 18°C, in a protocol as similar as a Channel swim to judge my readiness to swim the Channel, or alternatively, do my other dream swim (45 km round Hong Kong swim) as well. In the same period I would get ready for my working holiday, apply visas, etc.
May 2021 – August 2021: After I departed and started my working holiday, settle down in a coastal city ASAP and find a software developer job. I would join a training group there and continue swimming under the support of the community. The focus in the final months would mainly be acclimation to the environment there, and to improve my endurance, i.e. getting used to the Channel distance without undue fatigue. I would also do marathon swimming races in Europe in the season as well.
Swim total for January 2020: 50.5 km
At the time I made the bookings, sports centres and pools were closed as a precaution to a possible COVID-19 epidemic. At that time the epidemic was still mainly happening in mainland China and no one anticipated it to shut the whole world down. Squad training was moved to the beach and I was still joining. I swam about 12 km per week in early February after the post-race break, but because the pools were closed and I was not able to speed train, I didn't have much motivation. By the end of the month I was swimming about 15 km per week only, consisting of 2 squads session mid-week, and 2 weekend swims, all in open water. It was a warm winter and the water temperature in that month was around 17°C – 19°C, a bit warmer than my training target (16°C).
I was also training for my first marathon, Seoul International Marathon, scheduled in March as well. However, after Cold Half and my training break, I felt it hard to get back to running and I didn't enjoy training at all, when it started to get warm and humid. However, I joined a month of running classes in another triathlon training programme in February.
By the end of February, Hong Kong was still safe from the epidemic, however, it was already spread to South Korea, Iran and Italy, and my marathon due in March was cancelled. I did my last running session on 26 February and I had never run a single km for 4 whole months since then.
Swim total for February 2020: 53.5 km
The university pool was opened again early March. However, the squad training was still done in open water. As I prioritised my squad training, I didn't get back to the pool much. In the weeks I swam for 5 days, I did 2 squad sessions mid-week, 2 open water group swims on the weekend, and 1 swim in the pool. In retrospect I felt it might be a mistake. I kept swimming about 15 km each week.
By the middle of March, the epidemic had already spread to most of the Europe, the USA, etc. It became a global pandemic and the whole world were nearly shut within half a month. A bunch of cases were imported to Hong Kong from western countries as everyone was rushing the deadline before they would be quarantined upon entry. These were called the 2nd wave while the 1st wave were the occasional cases imported from mainland China since 23 January. Pools were closed again. Also, as my office started working from home, I was less motivated to go out and swim. I lived at a place where the water nearby was the harbour, while the place I normally swam in was close to my office. I got 5 consecutive days at the end of the month without swimming, which never happened since I started in 2019. Even before and after my big race, my period out of water was only 4 days.
Swim total for March 2020: 60.1 km
I initially placed my hope on summer for the pandemic to be over, like what happened in 2003, and bought the air ticket to Denmark in August in order to do my racing trip.
The work from home policy continued. I didn't even leave my home for consecutive days. Also I had a skin problem at that time so my family suggested me to move back. At that time I was living in the city and my family lived in a town very far away. As a result I did not swim most of the month. I got 10 consecutive days without swimming at all! In the weeks I did swim, I normally did about 16 – 20 km per week.
Also, I met a group of people who were willing to swim with me. They were mostly the same speed or slightly slower than me. The people I met before in the Sunday group were too fast for me and I had to use fins to keep up, and I often lagged behind in the return.
Swim total for April 2020: 49.2 km
I was still having hope in early May so I did a large block in the holidays, nearly 24 km in 3 out of 4 days of holiday. That made my training peak week of 28 km.
The COVID situation in Hong Kong was controlled in May. However, the virus had gone wild in western countries. My first training block had already gone because the pools were closed most of the time. Although I kept swimming in open water, my speed deteriorated as a result of lacking interval training. The hope for my trip to Europe was diminished and I winded down my training after peaking in the beginning of May. I decreased my swimming to about 3 times a week, then 2 times as week, as the sea temperature started to exceed 25°C, making it too hot for me to swim anything high intensity.
The pools in Hong Kong reopened mid-May, however it was already too hot for me to do any intense interval training in pool. As I was looking to improve my technique in my off-season I signed up a month of training in a swim club in June.
Swim total for May 2020: 51.4 km
I joined the training I signed up, 2 times per week. However, the training of that club seemed to be for pool races because their training sets consisted of all strokes and they had plenty of rest between sets, which were not like those in triathlon clubs. I didn't continue in July.
I also trained in my original squad 1 time per week, giving me in total 3 times a week of coached training sessions. Apart from them I also swam open water on the weekend, about once per week. However, as the weather became hot, the length of my open water swim shortened. I no longer did anything longer than 5 km, mostly in the range about 3 km. My average amount per week dropped to about 7 km.
Swim total for June 2020: 34.8 km
DWB TT and my swim update
Channel swim training the wrong way – July to November 2020

redpajama_set_name: RedPajamaCommonCrawl


text:
How to be a Buddhist Millionaire
9 practical steps to being happy in a materialist world
By Matt Jardine
Matt Jardine is a martial artist, entrepreneur, public speaker, podcaster, teacher, and the founder of Jardine Karate School. Matt has helped thousands of students discover their potential through his specially designed martial arts programs. He teaches in schools throughout London and has taught a diverse client base including Royalty.
Matt writes for Jiu Jitsu Style magazine, Europe's largest Brazilian jiu-jitsu magazine, and is the author of Mo and Lucy: Choices - a top ten rated PSHE resource for school students, and The Hardest Path, inspired by his 88 Temple pilgrimage of Japan.
He was a tennis coach to Princess Diana, and Princes William and Harry.
Matt has practiced meditation and other Eastern arts for over 25 years and now lives in London with his wife and Jack Russell.
Take a leaf out of Matt's book; free yourself of the fear of money and start living the life you want. - Moatez Jomni, British Paralympian
Matt Jardine, martial arts teacher and entrepreneur, has spent 20 years seeking the answer to one of life's ultimate conundrums: how can we lead an authentic, spiritual and creative life in a relentlessly money-centric world?
In this insightful book, he brings together Buddhist teachings, spiritual lessons and the advice and experience of a variety of experts and professionals; from a Paralympic athlete, to a West End musical star, to a city banker; and presents nine practical lessons to help us all discover our passion and make it pay.
With a light touch, he dispels the deep-rooted fears and limiting beliefs that hold us back, and forces us to question the very foundations of our lives and what really matters.
How to be a Buddhist Millionaire teaches us that money doesn't have to be a dirty word, and that if you search for happiness rather than the pot of gold, success is more likely to follow.
Published 2020 (Short Books)
ISBN: 9781780724249 - 288 pages - Paperback
Rights: Dutch (rest of world contact Red Rock Agency)


Source your product components made by STIEBEL ELTRON.
A very high level of vertical manufacturing gives STIEBEL ELTRON a depth of knowledge that extends right down to the smallest product details – and therefore also includes the individual components demanded by our business partners.
Complex heating systems for diverse industrial application areas – made in Germany.
Flanged immersion heaters in various outputs, designs and materials – tailored to customer requirements.
Specialised production for the processing of stainless steel and copper pipes.
Evaporator production with extensive production and process experience.
Vacuum, torch and induction soldering: the perfect soldering process for your application.


text:
Around $28,000 worth of catalytic converters stolen from one local business
ByKatie Katro
West Conshohocken police are looking for a group of people who stole 16 catalytic converters off of eight trucks.
WEST CONSHOHOCKEN, Pennsylvania (WPVI) -- West Conshohocken police are looking for a group of people who stole 16 catalytic converters off of eight trucks.
The incident happened Friday just after midnight, according to West Conshohocken's police chief, Michael Sinclair.
It happened at Aardvark Mobile Tours, which is a mobile event company.
When the pandemic hit and events were canceled, they adapted by turning their trucks into mobile testing and vaccine sites.
The company's CEO, Larry Borden, says this adds insult to injury, almost putting them out of work for the day to administer tests and vaccines.
A catalytic converter sits between the engine and the muffler in your exhaust. Borden said when an employee arrived Friday morning to turn on the truck, he heard an unusual sound.
"It was a shock this morning," said Borden.
Borden says surveillance video showed it didn't take long for the convertors to be swiped.
"I think it was like between 15 to 30 minutes, in and out," said Borden.
Surveillance video showed the group in action, including a car they showed up in and someone running behind one of the trucks.
"It is terrible," said Sinclair.
Sinclair says there's been a recent spike in catalytic converter thefts not just in the borough but regionally, as well.
"Basically, it's a quick hit job, a crime of opportunity, they cut these off, we believe they use what they call the precious metals," Sinclair added.
Borden says Aardvark is out thousands of dollars, estimated around $28,000 worth in damages.
"There's no doubt they knew exactly what they were doing. They cased the area. They came in, they were like surgeons, the cuts they made," said Borden.
Now his company is scrambling to find a way to replace them.
"We have to replace 16 catalytic converters, and they're not easy to find right now," said Borden.
The company was able to mobilize other vehicles Friday, to still get their work done, but they want these thieves caught.
If you have any information, please contact West Conshohocken police.
WEST CONSHOHOCKEN BOROUGH AUTO THEFT CRIME INVESTIGATION


text:
1 - 10 of 11 for Michael J. Glennon
National Security and Double Government by Michael J. Glennon 39 copies from $3.45
Constitutional Diplomacy by Michael J Glennon 32 copies from $4.97
When No Majority Rules: The Electoral College and Presidential Succession by Michael J Glennon 10 copies from $4.33
Franck & Glennon's Foreign Relations and National Security Law, 2D (American Casebook Series]) by Michael J, and Franck, Thomas M Glennon 8 copies from $3.89
Foreign Affairs Federalism: The Myth of National Exclusivity by Michael J, and Sloane, Robert D Glennon 9 copies from $87.66
Politics in America: Members of Congress in Washington and at Home by Alan Ehrenhalt 10 copies from $3.45
A Constitutional Law Anthology by Michael J. (Editor) Glennon 5 copies from $9.06
United States Foreign Relations Law: Documents and Sources by Michael J Glennon 4 copies from $3.49
Franck, Glennon and Murphy's Foreign Relations and National Security Law, 3D by Thomas M, and Glennon, Michael J, and Murphy, Sean D Franck 6 copies from $11.47
U.S. National Security Law: Cases, Materials, and Simulations, 4th by Thomas M, and Glennon, Michael J, and Murphy, Sean D Franck 5 copies from $45.98


text:
Sabrina Karim: Making UN peacekeeping more effective by removing barriers to women's participation
©Oxford University Press
Sabrina Karim
In their new book Equal Opportunity Peacekeeping: Women, Peace, and Security in Post-Conflict States Sabrina Karim and Kyle Beardsley go beyond the headlines on sexual exploitation and the numbers of women's participation to ask how the culture of UN peacekeeping needs to change if gender equality in peace operations is to become an attainable goal. Sabrina Karim recently spoke with GPOR's Jim Della-Giacoma about the book and the research on which it is based and what follows is an edited transcript of that conversation.
Jim Della-Giacoma (JDG): Your book opens with a description about how in some countries the foreign policy is becoming more feminist and the defense forces more gender equal. And yet you start with something of a skeptical tone as these changes are taking their time to come to UN peacekeeping. "Are blue helmets just for boys?", as you ask in the provocative title of your first chapter?
Sabrina Karim (SK): We frame the book noting the positive trends since UN Security Council Resolution 1325 was passed, such as the Hillary Doctrine in the United States and Sweden's feminist foreign policy. We suggest the UN has been a pioneer in promoting equality in security because of the multiple UNSC resolutions since 1325 in 2000. While they have got a head start, the book is focused on the current and future challenges. Our provocative question, "Are blue helmets just for boys?", sets the tone for book that looks at overcoming these challenges. We give a nod to the progress and innovations related to gender equality that have occurred in UN peacekeeping operations since 2000, but we want to make sure we don't get pigeon holed into seeing improved peacekeeping operations only in terms of increased women's participation. Gender equality in UN peacekeeping operations needs more than just increased women's participation; there needs to be cultural change.
JDG: What is the history of how some of these reforms that came from UNSC Resolution 1325 have been implemented by the UN Department of Peacekeeping Operations (DPKO)?
SK: Back in 2000, the vision of Resolution 1325 was centered on the three pillars of participation, protection and conflict prevention (though others might argue that there are more pillars). Our book focuses more on participation and protection, as there are still many challenges. Since 2000, there has been a call to increase women's participation in peacekeeping operations. We didn't see this become a mainstream issue that the UN Secretary-General talked about until after this resolution. For the past five years, the goal has been to try to increase women's participation to 10 per cent in military contributions and 20 per cent in police contingents. These targets have not yet been met (see graph below). More recent data since book was written shows that trends might be improving, particularly related to female military observers who are close to meeting the 10 per cent goal. Moreover, you do see the issue of increasing women's participation in some mandates, not all of them. Where there has been more movement is with the protection pillar, especially around sexual and gender based violence (SGBV). In several subsequent resolutions, such as 1820, 1888, 1889, and 1960, we do see a change in mandates with regards to SGBV and sexual exploitation and abuse (SEA) by peacekeepers along with the Zero Tolerance Policy in 2005. In 2015, we saw a move towards naming and shaming troop and police contributing countries whose personnel had been found to engage in sexual exploitation and abuse. With respect to gender mainstreaming, efforts have been a more confusing for policymakers in DPKO to operationalize. There is usually a civilian gender team and then there are also gender focal points in the military and police, usually women. Together, they are responsible for mainstreaming gender, even though it is sometimes unclear what this means. Individual missions have more discretion in how they operationalize this term.
JDG: What is the pattern of deployment for women in UN peacekeeping operations?
SK: Low participation of women in UN peacekeeping operations is something that is very widely noted, but in our book, we look beyond just the numbers to where female peacekeepers are deployed. We find that they tend to be in the safest missions and not necessarily where they are most needed. There are higher proportions of uniformed women peacekeepers in Kosovo and Liberia, instead of places like the CAR and DRC, where the UN has argued they are most needed because of the levels of sexual violence there. There is a gender protection norm, which is the idea that women still need to be protected even though they are in the military or police. This perception means they don't end up being on the front lines where peacekeepers are needed, whether to the particular countries that have experienced high levels of violence or they may be stuck in an office doing administrative work. We talked to decisions makers in the Bangladesh military, for example, who while they have sent all female contingents through their police, said they do consider the safety of women when deciding where to deploy women in the military.
JDG: There are gender imbalances in most security institutions around the world. How does this impact the participation rate of women in UN peacekeeping missions?
SK: One of the common reasons that the UN and contributing countries will give for sending more women is that they simply don't have women in their military and police forces. While this may be more likely the case for the military, it is not the case for police. We aggregated data on the proportion of women in police forces and in militaries globally and then looked at whether or not the police forces around the world that had higher numbers of women are the ones contributing more to UN peacekeeping operations and they are not. There is something else going on for police contributions. We did find a correlation for military contributions. That is, the more females present in a contributing country military force, the more likely they are to send women to missions. We think this is because most military contributions occur through troop contributions, and women are either in units or they are not. In contrast, for police contributions, and perhaps military observers, women usually apply or are selected, which means that the number of women in the police force matters less.
JDG: Once the few women are deployed, do they experience discrimination in missions?
SK: While allegations of SEA receive a lot of coverage, what is not talked about is the experience of women in UN peacekeeping operations, including the discrimination and harassment many face. I don't think I have ever seen any articles in the media or studies looking at the experiences of female peacekeepers and this is one of the bigger contributions of the book. These problems are symptoms of a broader cultural problem that all of societies are facing. It is exacerbated in the military and police because certain masculine traits are privileged over feminine traits in these organizations. Men are seen to be natural warriors and more competitive, whereas women are seen to need protection. If feminine traits such as the ability to listen, communicate, and empathize were equally privileged we would have equality in culture.
JDG: The case study on the UN Mission in Liberia (UNMIL) is one of the unique things about your book, what did you find when studying the experiences of women in peacekeeping in that mission?
SK: UNMIL provided an ideal study in terms of women's experiences and I was able to interview a diverse set of women. It is touted as one of the more successful cases of women's integration into peacekeeping missions because of the all-female police unit that was deployed there in 2007. My favorite part about writing the book was getting to spend a lot of time with female peacekeepers and learning about their lives and experiences in the mission and back in their home country. It was eye opening to me to learn a little about the uphill battles that they face in their jobs and the amount of optimism they have about what they contribute to the mission. Globally, they are sent to safe missions and not where they are needed. Once deployed, they are often further restricted in their movements. In the peacekeeping mission, the number one complaint, almost unanimously, was the lack of mobility and their inability to engage with communities. Sometimes it was because it wasn't part of the mandate or their job description, but there seems to be a discrepancy between what the women in peacekeeping page on the DPKO website says versus what is actually happening on the ground. It assumes there is a lot engagement between female peacekeepers and locals and this is just not the case. It is not happening and it is the number one complaint of female peacekeepers.
JDG: What stories stuck out about the lives of women in this mission?
SK: I befriended a number of female peacekeepers and heard about their stories and a few of them stick out in terms of discrimination and even humiliation. There is one female from a sub-Saharan country who was the highest serving woman from her country. She was assigned as the deputy to the civil military division, where there was a Western male colonel in charge. She didn't necessarily have the exact computing skills that he needed, but instead of using her for the skills she did have he would constantly set her up to fail and humiliate her in front of other peacekeepers. He would make her do presentations that she was unprepared to do and the talk behind her back and make everyone laugh at her. I saw this and it was very painful to watch. She was the only woman in that entire unit.
Gender equality in UN peacekeeping operations needs more than just increased women's participation; there needs to be cultural change.
Outside of the mission, when women are engaging with locals, such as the female police officers assigned to train the domestic police force, they have to deal with borderline harassment and humiliation. A few of them would complain they would often get marriage proposals and were not taken seriously by their local counterparts. Then there was the problem of "Old Boy's Networks" and the ability of men to socialize after hours, but not women due to rules and lack of access to vehicles etc.
I was surprised to find that women were also part of the problem. In the book, there is a story about this initiative in the mission where the female military and police officers, one of whom was a gender focal point, wanted to get together to do a community project with females living in an ex-combatant community. More senior women in UNPOL shot the project down as they felt they had not been properly included in the process. It is not just a case of men versus women, it is a culture and so women can be oppressive to women as well. The idea is to change the culture.
JDG: And what are some of the differences you observed between male and female peacekeepers?
SK: Despite all these challenges, the women unanimously believe they make a unique difference in missions, they believe they add value, and they were very optimistic about their role. The motivations for women to join peacekeeping missions and even the militaries and police back home were different for women and men. Whereas men often talked about the money and promotions as a reason for serving with a UN peacekeeping mission, women talked about helping people and going on an adventure. I did see the unique things women could do in a peacekeeping mission. I went on numerous patrols and one time I witnessed a female UNPOL peacekeeper mediate between two male LNP officers and a rape victim. There was a genuine effort by this female officer to resolve this case and when I interviewed her later she recalled how she had intervened as she felt solidarity with this woman.
JDG: And how did local people perceive female peacekeepers in Liberia?
SK: It is another innovation of book that we looked at local perceptions of women peacekeepers. Generally, there is a failure to take public opinion into consideration when we think about peacekeeping effectiveness. With fewer women in peacekeeping operations because of the barriers to participation, it is a little harder to gauge what is the reaction to female peacekeepers because of their lack of visibility. In our survey, there is some limited evidence that there is a preference for female peacekeepers and they are perceived as better. The survey was only done in the capital Monrovia and not the entire country, but in the city, most Liberian women did not have contact with female peacekeepers. There is very little contact and we debunked an assumption made by the UN that just because you have female peacekeepers they communicate with local women and the problems will be solved. Yet, there are definitely contributions made by female peacekeepers at the local level. Female peacekeepers also participated in institution building roles with the Liberian National Police. They were instrumental in developing the gender and the women and children's protection units as well as the LNP's sexual harassment policy. While the public interactions may be limited, behind the scenes there are many things going on.
JDG: Does this all add up to Resolution 1325 actually being implemented or is there a lot of box ticking going on without any of the culture change that you've argued needs to take place in UN peacekeeping missions?
SK: I am a little bit of a pessimist when it comes to this question. Similar to when it comes to different trends throughout the 1990s such as good governance and democracy promotion, I fear that gender equality might be another one of these trends and just be another box to be ticked. I see this because of the kinds of indicators that are reported. It is the number of women. This is something that can be easily counted. We make this point in the book that the focus on women's participation is the only thing that has concretely manifested itself through UN Security Council resolutions through time with respect to gender and peacekeeping. We critique this point out that it is not just about women's participation but real change means changing the culture of peacekeeping missions. For example, there is a common assertion, even in the Zeid Report, that increasing the proportion of female peacekeepers will lead to reduced levels of sexual exploitation and abuse by peacekeepers. This is simply not the case. Instead, in the book, we find that when there is a norm of gender equality in missions, it is likely to have fewer allegations of sexual exploitation and abuse. For this reason and many others, it is important to focus efforts and reforms on cultural change. This is not to say that we shouldn't focus on operationalization or increasing the number of women in peacekeeping and in senior positions, but it is more than that and this is what the book focuses on.
JDG: How do we bring about this cultural change in missions?
SK: One of the reasons this is so difficult is that changing culture is nearly impossible to measure. The recommendations from the 1325 Study or the HIPPO report are important but they are sweeping. In the book, we focus on the smaller things that can be done to chip away at this culture. There are five areas where there is room within missions to start changing this.
First, there's leadership. No change will be possible without strong leadership, especially in the military and police. There needs to be care about how SRSG's, Force Commanders, and Police Commanders are selected with an eye towards gender equality. They obviously have to have certain qualifications to be considered for these positions, so why not include another standard for what they need to do to demonstrate how they have implemented gender mainstreaming in their own country or in their career. Questions can be asked at an interview stage about what have they done to address gender issues in their own institution? If missions have the right leaders, there should be a trickle down effect. If the force commander or police commissioner values this idea then it can be mandated down the chain of command.
Second, there can be changes to standards of recruitment as well as standards more broadly. Thinking about equality between traits. Right now, there is a privileging of recruitment based on masculine traits. Biologically, there are height, weight, and strength requirements to enter the military or police. There are sociological traits such as particular skills that you have to have that are all gendered male one related to rationality or over-confidence—think of the values of an "alpha male," but if we also considered traits that are feminine, such as how well people listen, communicate, and empathize, these could also be included in recruitment. There are driving tests and computing test for peacekeepers, so why not test for gender equality or these other skills such as cooperation, listening, and communication that are needed for peacekeeping.
Third, there is promotion and demotion. It is very difficult to punish somebody who has committed sexual exploitation and abuse in a mission. They often just get sent home and there is usually no trial. Getting sent home can be a punishment in itself but there are still other ways to punish and promote good behavior for smaller offences. For example, lucrative placements can be used as an incentive for good behavior. Peacekeepers will request particular placements, especially for police or military observers. Awarding particular placements could be one way to leverage good behavior. Mission extensions could be used in similar fashion. Also not giving medals to certain people and being more selective about this. The UN has started naming and shaming contributor countries. There is more leverage for promotions and demotions within missions and it is important to find those levers.
Fourth, there are role models, mentors, and networks. This is focused on empowering women within missions. If you want to increase women's participation and help women up the ladder, then women are more likely to apply for positions in a peacekeeping mission if they have a mentor to help them through the process. This is an alternative to the old boys networks that have developed in peacekeeping missions.
Lastly, there is training and professionalization. This is something that is kind of happening with regards to gender and peacekeeping missions. There is one unit in the two-week training on gender mainstreaming, but that's about it. It is not done in the best way. It shouldn't even be singled out as its own module, but rather integrated into every module and then it might be taken more seriously. Those kinds of trainings should be done with the Force Commander or other leadership should be involved with it so that participants can see that it is a serious matter. Moreover, one of the reasons that women are prohibited from joining missions is that they don't have the skills with computers, driving a stick shift (manual transmission vehicle) or using a weapon. Professionalization programs for women in contributing countries are helpful to show they have the same skills as men. The Nordic countries, for example, have training program specifically for women of militaries and police forces in places such as Ghana. They could be an example for the rest of the world.
JDG: For those us working on peacekeeping policy and public debate as well as those of us in the media, how might we have more nuanced discussions about gender and peacekeeping? What mistakes might we be making in the way we talk about this issue?
SK: Most of the mainstream media reporting on gender is about sexual exploitation and abuse. This is what makes the front-page news. Moving away from this and the trope of women's participation and delving deeper into the questions. Rather than simply reporting there are not enough women, they should be delving deeper into what is going on. The story is much more nuanced than there just aren't enough women in the military and police in troop and police contributing countries. They should be asking: Where are women going on peacekeeping operations, what are they doing there, and what are their experiences when they get there? We want to pick away at the barriers they face. I don't think I have ever seen a story about women's experiences on mission. We see that peacekeepers can be predators against local women but we don't see that female peacekeepers are also facing challenges such as harassment and discrimination. It would be interesting to bring peacekeeping voices to the media instead of just policy maker voices. There needs to be a broader discussion about the quality of peacekeeping missions. Peacekeeping effectiveness is not just about gender and peacekeeping. Because there is so much fear in DPKO that they cannot get enough troops and police from contributing countries they don't want to criticize any country or draw attention to any problem otherwise they won't contribute. There is a fear of moving towards quality peacekeeping at the expense of quantity. I have been surprise there haven't been any in-depth investigations into those countries that are listed since 2015 on the naming and shaming list. If they name and shame these countries, then they won't contribute to peacekeeping anymore and that will be a problem.
JDG: In an era when peacekeeping is shrinking in numbers, does it give you some optimism that this might be the time to focus on quality rather than quantity?
SK: I commend US Ambassador to the UN Nikki Haley's goal to reform peacekeeping as long as it means not taking away resources from valuable programs and reducing the size and number of missions that are important. This is a good time for peacekeeping reform of all kinds and I hope reform includes equal opportunity peacekeeping because it creates a much more efficient system. If women are prevented from doing the things that they want to do and they are capable of doing, then they are not making as much of a difference as they could because of the barriers that I have mentioned. If those barriers are taken away, it will make peacekeeping more efficient and more effective. To improve women's participation in missions, cultural change is needed, and this is what equal opportunity peacekeeping is all about.
Sabrina Karim will start a new job as an assistant professor in the Government Department at Cornell University in the fall of 2017. She is currently a U.S. Foreign Policy and International Security Fellow at the Dickey Center for International Understanding at Dartmouth College. | Twitter: @sabrinamkarim
Jim Della-Giacoma is the Deputy Director of the Center on International Cooperation and Editor-in-Chief of the Global Peace Operations Review. | Twitter: @jimdella
Tags : Gender | Gender-based violence | Jim Della-Giacoma | Sabrina Karim | UN Secretary-General | UNSC Resolution 1325 | UNSC Resolution 1820 | UNSC Resolution 1960
← Cedric de Coning: Adapting the UN Peacekeeping Doctrine to Stabilization Missions, Protection of Civilians mandates and New Threats


text:
Creating A World Class Candidate Experience Captain's Table Forum
Better Practice, Captain's Table, Improve Performance, Leadership, Recruitment Best Practice, Sales
Recruiters' fear of transparency blocking real-time engagement Shortlist Thursday 25 July 2019 Recruiters now have the ability to give applicants and candidates real-time updates in the vein of Uber and other platforms, but many are shunning…
https://www.navigatorconsult.com/wp-content/uploads/2019/07/Creating-A-World-Class-Candidate-Experience.png 150 300 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2019-07-26 11:29:352020-01-29 12:03:59Creating A World Class Candidate Experience Captain's Table Forum
Employers increasing uptake of offshoring model
Offshoring, Outource, Recruitment, Recruitment Best Practice, Staff
From Shortlist Industry news & market intelligence, In-house recruitment Australian employers are overcoming misgivings about offshoring and are moving towards solutions that include a mix of talent models, says the head of Alexander…
https://www.navigatorconsult.com/wp-content/uploads/2019/03/Offshore-Resourcing.jpg 380 380 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2019-07-19 07:57:512019-07-19 08:03:12Employers increasing uptake of offshoring model
10 Questions To Determine The Health Of Recruitment Businesses
Cost savings, Improve Performance, Leadership, Motivation, Recruitment, Recruitment Best Practice, Sales
An industry advisor has developed a new checklist to help agency leaders assess their business's performance and highlight early warning signs of distress. From Shortlist March 2019 Navigator Consulting MD Tony Hall created the 10-question…
https://www.navigatorconsult.com/wp-content/uploads/2018/03/Untitled-design-2.png 250 250 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2019-03-29 11:49:562020-01-29 12:14:4210 Questions To Determine The Health Of Recruitment Businesses
Technology hype blinds leaders to marketing Return On Investment
Better Practice, Improve Performance, marketing, Recruitment Best Practice
Technology hype blinds leaders to marketing ROI From Shortlist Recruitment leaders are wasting too much money and effort on marketing that doesn't align with their business fundamentals, often blindly following trends that deliver…
https://www.navigatorconsult.com/wp-content/uploads/2019/02/Captains-Table-Page-Tile-300x150-1.png 150 300 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2019-03-01 10:07:482020-01-29 12:15:51Technology hype blinds leaders to marketing Return On Investment
Are you satisfied at work? 10 Simple questions to determine whether its time for a change.
Most people spend a significant proportion of their waking hours at work or at least thinking about work. This is even more so for those who are owners or at a senior level within any business. The recruitment industry is no exception. Having…
https://www.navigatorconsult.com/wp-content/uploads/2019/01/Untitled-design-14.jpg 312 820 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2019-01-18 10:22:282019-01-30 11:47:29Are you satisfied at work? 10 Simple questions to determine whether its time for a change.
Shortlist Reports: Is The 360 Recruitment Model Broken?
Better Practice, Cost savings, Improve Performance, Leadership, Motivation, Offshore, Offshoring, Outource, Recruitment, Recruitment Best Practice, Staff
From Shortlist: Thursday 04 October 2018 2:47pm Recruitment's shift away from employing 'outdated' 360-degree consultants is potentially the most important transformation the industry will face, according to an advisor. The…
https://www.navigatorconsult.com/wp-content/uploads/2018/10/shortlist-logo.png 531 531 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2018-10-05 08:54:352020-01-29 12:18:30Shortlist Reports: Is The 360 Recruitment Model Broken?
Recruitment Leaders Falling Short In Key Planning Areas
Better Practice, Improve Performance, Leadership, Recruitment, Recruitment Best Practice, RIBCIX
From Shortlist 30 August 2018 Recruitment agency leaders are meticulous around developing budgets and financial plans, as well as measuring consultant activity, but more work is needed to improve performance across all areas of the business,…
https://www.navigatorconsult.com/wp-content/uploads/2018/09/Results-Fall-Short.jpg 794 1120 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2018-09-04 12:20:282018-09-04 18:08:11Recruitment Leaders Falling Short In Key Planning Areas
360 Recruiter Model Is Broken (And 12 Solutions To Fix It)
Better Practice, Cost savings, Leadership, Offshore, Outource, Recruitment, Recruitment Best Practice
By Tony Hall, Managing Director, Navigator Consulting Great recruiters who bill well and stay for many years are now rare as hen's teeth. They are unlikely to move from a profitable and happy desk which they probably built themselves over…
https://www.navigatorconsult.com/wp-content/uploads/2018/08/broken-bad-link-ss-1920.jpg 1080 1920 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2018-08-28 16:04:422018-08-29 07:05:09360 Recruiter Model Is Broken (And 12 Solutions To Fix It)
Recruitment Leaders Forecasting Massive Growth
Better Practice, Leadership, Recruitment, Recruitment Best Practice, RIBCIX
From Shortlist, Wednesday 22 August 2018 Agency leadership, Research, analysis & reports Recruitment leaders across the board are reporting record financial results, with staffing challenges the primary obstacle to realising further…
https://www.navigatorconsult.com/wp-content/uploads/2018/08/yourstory-india-growth.jpg 400 800 Tony Hall https://www.navigatorconsult.com/wp-content/uploads/2015/08/logo1.jpg Tony Hall2018-08-24 10:26:212018-09-04 18:09:07Recruitment Leaders Forecasting Massive Growth


text:
Q: Average number of pairwise different elements between N lists In the following problem I have a nested list wp. The N lists in wp contain integer numbers. I want to compute as fast as possible the average number of pairwise different elements between the lists, e.g.
N = 3
wp[0] = [0,1,2]
wp[1] = [0,1]
wp[2] = [3]
--> Different elements (wp[0],wp[1])=1
--> Different elements (wp[0],wp[2])=4
--> Different elements (wp[1],wp[2])=3
---> Avg. pairwise different elements = (1+4+3)/3=2.666

Currently my code is the following:
avg_distance = 0.0
for x1 in range(N):
    for x2 in range(x1 + 1, N):
        distance_temp = 1.0 * len(list(set(wp[x1]) ^ set(wp[x2])))
        avg_distance += distance_temp
avg_distance = 1.0 * avg_distance / (1.0 * N * (N - 1.0) / 2.0)

This is by far the most significant bottleneck in my code. I'm wondering if it could be done faster? I actually use this part within a function that has a numba decorator. Thanks!

A: Following 2x faster on shorter lists, 3X on longer lists.
Revised Code
from itertools import combinations as comb

def calc_revised(wp):
  N = len(wp)
  return sum(len(x ^ y) for x, y in comb([set(w) for w in wp], 2))*2/(N*(N-1))

Testing
Posted code as a function
def calc_posted(wp):
  avg_distance = 0.0
  N = len(wp)
  for x1 in range(N):
      for x2 in range(x1 + 1, N):
          distance_temp = 1.0 * len(list(set(wp[x1]) ^ set(wp[x2])))
          avg_distance += distance_temp
  avg_distance = 1.0 * avg_distance / (1.0 * N * (N - 1.0) / 2.0)
  return avg_distance

Timing test original wp (using timeit)
# Data
wp = [[0,1,2], [0,1], [3]]

# Timing
from timeit import timeit
count = 100000
print(timeit(lambda:calc_posted(wp), number=count))
print(timeit(lambda:calc_revised(wp), number=count))
# Output
# 2.2190305839994835 for calc_posted
# 1.1981851930004268 for calc_revised
#
# Revised code ~2X faster

Timing test wp with 1K random sublist, random lengths from 1 to 10
# Data Generation
from random import sample
from random import randint
T = 1000
wp = [sample(range(1, 100), randint(1, 10)) for _ in range(T)]

# timing
from timeit import timeit
count = 1
print(timeit(lambda:calc_posted(wp), number=count))
print(timeit(lambda:calc_revised(wp), number=count))
# Output:
# 3.8808193380000375 for calc_posted
# 1.2002467920001436 for calc_revised
#
# Revised code ~3X faster

List Comprehension
Version based upon list comprehension.
Timing was comparable to calc_revised
def calc_list_comp(wp):
  N = len(wp)
  set_w = [set(w) for w in wp]
  return sum(len(set_w[i] ^ set_w[j]) for i in range(len(set_w)) for j in range(i+1, N))*2/(N*(N-1))

redpajama_set_name: RedPajamaStackExchange


It's all about the joy.
This year kicked off with a new feel for my photography. December I officially closed my photography business. Say what? Yup. The client work I have now is much more selective. I'm not going to get in to the nitty gritty of the "Why?" right now, but it boils down to this "I'm more of an artist than an entrepreneur." So with the marketing, client qualifying, accounting, and all that goes with a business out of the way I am able to shoot what I want when I want.
So for fun, I have jumped in to Macro Photography. Shooting small things up close and personal. I still do and LOVE my portrait work. That will never change. People are interesting. We all look, act, and feel different; so I expect boredom will never peek it's ugly head with that.
Just like with portraits I have successes and failures, trials and errors. I miss things. I'm so focused on one thing, that I lose the bigger picture... Like the one below..I did not see the spider in this shot when I shot it. My focus was the spikey ball of the plant.
I know what you're thinking "How could you miss that?" It's easier than you think. I was concentrating on nailing focus where I wanted it. Lesson learned.. you would think. Nope! I missed this one too. I was curious as to why the bee was dangling. I knew he was dead, but figured his leg was caught on the petal somehow.
So, here I am, learning, seeing, and not seeing apparently. I never get sick of learning this craft. There's always something that I never heard of before, tried, or achieved yet. Whatever is burning inside you, feed that fire. Don't go on and on dreaming about the dream and just live it already. Why does everyone think you have to get famous or make a lot of money doing what you love? You know that saying "Do what you love and you'll never work another day in your life." Let's face it, we just don't want to work. I kid, if you can make a living doing what you love go for it! If you can't or really don't want to at this point in your life at least still do it. Remember what Dr. Who said "Some people live more in 20 years than others do in 80. It's not the time that matters, it's the person."
My friend makes the Arkham Knight Harley Quinn inspired baseball bat. She asked me for some product shots, and had a model already. I had to do this shoot, there was no way around it. Wicked awesome cosplayers. Let me tell you what, I had a blast. I got to play with angles and light in a whole new way. You should check out her Etsy store here.
I was worried when they were running behind, but it worked out perfectly. The lighting was awesome and the colors popped. If we were shooting earlier, I would not have gotten the look out of The Polk Theater marquee that I got.
I put a bare speed light behind her, because I knew the marquee would not illuminate her, but I wanted it to look like it did. I got some nice rim light and the effect I was after. I lit her from the front right with a speed light in a softbox umbrella. This allowed me to expose everything in the frame.
It was a good night, I think everyone enjoyed themselves.


Many techniques are available for sediment examinations, however few techniques combine non-destructive features, a wealth of important information available down to the microscopic scale, and time for examination that is short enough to offers large sample throughput, and not to damage the valuable sediment cores during examination. A combination of these features has made XRF core scanning the standard tool for examination of sediment cores, often used as a first sample overview from which scientists can decide for the following steps to take when examining their samples. With onboard core scanner installations, core examinations can even be performed while the core sampling vessel is still at the sampling spot, and an overview scan with centimeter steps can be performed within a few minutes, depending on the choice of XRF scanner. Data on the variation of different elements along the cores, when combined in a way to describe proxies, provide much information of the origin of the different sediment sections. The list of aspects on climate related information that can be retrieved through proxies has grown much in the last few years, and 60+ proxies have been listed.
Here are shown a few data examples from Itrax Core Scanner. These data are from analysis of a section of a marine sediment core from the Arctic,and give an idea of the level of accuracy and detail of core data that can be gathered in short time . The photos were recorded with Itrax Core Scanner. The two photos show the same 200 millimeter long sediment section. In the left one of these, two element profiles in Red and Blue are overlaid on the photo, showing the variation of Silica (Si) concentration along the sample as determined in two consecutive scans. The Si concentration is on average roughly 10%. The right photo shows the same sample section, here with two Manganese (Mn) profiles overlaid. The two Mn profiles were registred during the same two scans as for Si. Together they give an idea of the level of reproducibility for light as well as heavier elements, when scaning with one second of measuring time per point. The Mn concentration is on average roughly 0.07% (700 PPM). The elements that were determined simultaneously in one scan were Al, Si, S, Cl, K, Ca, Ti, V, Cr, Mn, Fe, Ni, Cu, Zn, As, Br, Rb, Sr, Zr, Ba, La and Pb (only Si and Mn shown). Imprints from the Magnetic Susceptibility measurement appear as circular marks on the sample surface, while Itrax optical, radiographic and XRF analyses do not touch the surface during analysis.These measurement were conducted with an Itrax Core scanner equipped with our top-of the-line XRF offering a count rate of up to 300.000 x-ray photon counts per second, thereby offering very fast and at the same time presice analyses. Please click this link to open a larger sample image in a separate window Core material with courtesy of Dr. Richard Gyllencreutz, Stockholm University. From IODP Expedition LOMROG III 2012, Lomonosov ridge, off Greenland. Sampled at 4228 meters depth.


text:
Home News Brian Blair To Receive 2015 Lou Thesz Award, WWE Stock Update, Mick...
Brian Blair To Receive 2015 Lou Thesz Award, WWE Stock Update, Mick Foley News, More
— At the closing bell on Tuesday, WWE stock was at $13.91 per share.
— WWE Hall of Famer Mick Foley posted a message on Facebook today noting
that his "I Am Santa Claus" movie will premiere at the 2014 Hollywood Film
Festival. The event will take place on Sunday, October 19th.
— The National Wrestling Hall of Fame Dan Gable Museum has announced that
Brian Blair is the first honoree for its 2015 George Tragos/Lou Thesz
Professional Wrestling Hall of Fame. Blair will be the 2015 recipient of the Lou
Thesz Award, which is given to an individual in wrestling who has taken the
skills of the sport into the realm of public service.
The announcement noted that Blair is currently the president of the
Cauliflower Alley Club, a non-profit fraternal organization, comprised of both
retired and active professional wrestlers and boxers in North America. Blair
also has over 7000 documented hours of community service with over 20 different
organizations.
"I am both honored and humbled to be recognized with the coveted Lou
Thesz Award from the George Tragos/Lou Thesz Professional Wrestling Hall of Fame
in Waterloo," said Blair. "Lou Thesz is a legend and one of
the toughest to ever step foot in a ring. July 10th cannot come soon enough for
Brian Blair
Mick Foley
WWE Stock
Robert Stone
Robert Strauss
Strauss is currently signed to WWE under the name Robert Stone. He is best known for his time in Total Nonstop Action Wrestling under the ...


Watchfullmovie Alita Battle Angel netflix full movie, Alita Battle Angel netflix online free, Alita Battle Angel , Watchfullmovie Alita Battle Angel netflix, Alita Battle Angel netflix Watchfullmovie, watch movies online, watch Alita Battle Angel netflix online, Watch Alita Battle Angel netflix. Watch thousands of Free Movies starring your favorite actors. You can find them all on this channel powered by Uflixit.COM. Best Site To Watch Free Movies Online With Daily Update Content!