///////////////////////////////////////////////////////////////
//  Copyright 2012 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_BIT_HPP
#define BOOST_MP_CPP_INT_BIT_HPP

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4319)
#endif

namespace boost{ namespace multiprecision{ namespace backends{

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
void is_valid_bitwise_op(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::int_<checked>&)
{
   if(result.sign() || o.sign())
      BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
void is_valid_bitwise_op(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& , const mpl::int_<unchecked>&){}

template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
void is_valid_bitwise_op(
      const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const mpl::int_<checked>&)
{
   if(result.sign())
      BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
void is_valid_bitwise_op(
   const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const mpl::int_<checked>&){}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
void is_valid_bitwise_op(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const mpl::int_<unchecked>&){}

template <class CppInt1, class CppInt2, class Op>
void bitwise_op(
   CppInt1& result,
   const CppInt2& o,
   Op op, const mpl::true_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
{
   //
   // There are 4 cases:
   // * Both positive.
   // * result negative, o positive.
   // * o negative, result positive.
   // * Both negative.
   //
   // When one arg is negative we convert to 2's complement form "on the fly",
   // and then convert back to signed-magnitude form at the end.
   //
   // Note however, that if the type is checked, then bitwise ops on negative values
   // are not permitted and an exception will result.
   //
   is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
   //
   // First figure out how big the result needs to be and set up some data:
   //
   unsigned rs = result.size();
   unsigned os = o.size();
   unsigned m, x;
   minmax(rs, os, m, x);
   result.resize(x, x);
   typename CppInt1::limb_pointer pr = result.limbs();
   typename CppInt2::const_limb_pointer po = o.limbs();
   for(unsigned i = rs; i < x; ++i)
      pr[i] = 0;

   limb_type next_limb = 0;

   if(!result.sign())
   {
      if(!o.sign())
      {
         for(unsigned i = 0; i < os; ++i)
            pr[i] = op(pr[i], po[i]);
         for(unsigned i = os; i < x; ++i)
            pr[i] = op(pr[i], limb_type(0));
      }
      else
      {
         // "o" is negative:
         double_limb_type carry = 1;
         for(unsigned i = 0; i < os; ++i)
         {
            carry += static_cast<double_limb_type>(~po[i]);
            pr[i] = op(pr[i], static_cast<limb_type>(carry));
            carry >>= CppInt1::limb_bits;
         }
         for(unsigned i = os; i < x; ++i)
         {
            carry += static_cast<double_limb_type>(~limb_type(0));
            pr[i] = op(pr[i], static_cast<limb_type>(carry));
            carry >>= CppInt1::limb_bits;
         }
         // Set the overflow into the "extra" limb:
         carry += static_cast<double_limb_type>(~limb_type(0));
         next_limb = op(limb_type(0), static_cast<limb_type>(carry));
      }
   }
   else
   {
      if(!o.sign())
      {
         // "result" is negative:
         double_limb_type carry = 1;
         for(unsigned i = 0; i < os; ++i)
         {
            carry += static_cast<double_limb_type>(~pr[i]);
            pr[i] = op(static_cast<limb_type>(carry), po[i]);
            carry >>= CppInt1::limb_bits;
         }
         for(unsigned i = os; i < x; ++i)
         {
            carry += static_cast<double_limb_type>(~pr[i]);
            pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
            carry >>= CppInt1::limb_bits;
         }
         // Set the overflow into the "extra" limb:
         carry += static_cast<double_limb_type>(~limb_type(0));
         next_limb = op(static_cast<limb_type>(carry), limb_type(0));
      }
      else
      {
         // both are negative:
         double_limb_type r_carry = 1;
         double_limb_type o_carry = 1;
         for(unsigned i = 0; i < os; ++i)
         {
            r_carry += static_cast<double_limb_type>(~pr[i]);
            o_carry += static_cast<double_limb_type>(~po[i]);
            pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
            r_carry >>= CppInt1::limb_bits;
            o_carry >>= CppInt1::limb_bits;
         }
         for(unsigned i = os; i < x; ++i)
         {
            r_carry += static_cast<double_limb_type>(~pr[i]);
            o_carry += static_cast<double_limb_type>(~limb_type(0));
            pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
            r_carry >>= CppInt1::limb_bits;
            o_carry >>= CppInt1::limb_bits;
         }
         // Set the overflow into the "extra" limb:
         r_carry += static_cast<double_limb_type>(~limb_type(0));
         o_carry += static_cast<double_limb_type>(~limb_type(0));
         next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
      }
   }
   //
   // See if the result is negative or not:
   //
   if(static_cast<signed_limb_type>(next_limb) < 0)
   {
      double_limb_type carry = 1;
      for(unsigned i = 0; i < x; ++i)
      {
         carry += static_cast<double_limb_type>(~pr[i]);
         pr[i] = static_cast<limb_type>(carry);
         carry >>= CppInt1::limb_bits;
      }
      if(carry)
      {
         result.resize(x + 1, x);
         if(result.size() > x)
            result.limbs()[x] = static_cast<limb_type>(carry);
      }
      result.sign(true);
   }
   else
      result.sign(false);

   result.normalize();
}

template <class CppInt1, class CppInt2, class Op>
void bitwise_op(
   CppInt1& result,
   const CppInt2& o,
   Op op, const mpl::false_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
{
   //
   // Both arguments are unsigned types, very simple case handled as a special case.
   //
   // First figure out how big the result needs to be and set up some data:
   //
   unsigned rs = result.size();
   unsigned os = o.size();
   unsigned m, x;
   minmax(rs, os, m, x);
   result.resize(x, x);
   typename CppInt1::limb_pointer pr = result.limbs();
   typename CppInt2::const_limb_pointer po = o.limbs();
   for(unsigned i = rs; i < x; ++i)
      pr[i] = 0;

   for(unsigned i = 0; i < os; ++i)
      pr[i] = op(pr[i], po[i]);
   for(unsigned i = os; i < x; ++i)
      pr[i] = op(pr[i], limb_type(0));

   result.normalize();
}

struct bit_and{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a & b; } };
struct bit_or { limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a | b; } };
struct bit_xor{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a ^ b; } };

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
   eval_bitwise_and(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   bitwise_op(result, o, bit_and(),
      mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
   eval_bitwise_or(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   bitwise_op(result, o, bit_or(),
      mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
   eval_bitwise_xor(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   bitwise_op(result, o, bit_xor(),
      mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
}
//
// Again for operands which are single limbs:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
   eval_bitwise_and(
      cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
      limb_type l) BOOST_NOEXCEPT
{
   result.limbs()[0] &= l;
   result.resize(1, 1);
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
   eval_bitwise_or(
      cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
      limb_type l) BOOST_NOEXCEPT
{
   result.limbs()[0] |= l;
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
   eval_bitwise_xor(
      cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
      limb_type l) BOOST_NOEXCEPT
{
   result.limbs()[0] ^= l;
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
   eval_complement(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
   // Increment and negate:
   result = o;
   eval_increment(result);
   result.negate();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
   eval_complement(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   unsigned os = o.size();
   result.resize(UINT_MAX, os);
   for(unsigned i = 0; i < os; ++i)
      result.limbs()[i] = ~o.limbs()[i];
   for(unsigned i = os; i < result.size(); ++i)
      result.limbs()[i] = ~static_cast<limb_type>(0);
   result.normalize();
}

template <class Int>
inline void left_shift_byte(Int& result, double_limb_type s)
{
   limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
   limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
   unsigned ors = result.size();
   if((ors == 1) && (!*result.limbs()))
      return; // shifting zero yields zero.
   unsigned rs = ors;
   if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
      ++rs; // Most significant limb will overflow when shifted
   rs += offset;
   result.resize(rs, rs);
   rs = result.size();

   typename Int::limb_pointer pr = result.limbs();

   if(rs != ors)
      pr[rs - 1] = 0u;
   std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT);
   std::size_t len = std::min(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes);
   if(bytes >= rs * sizeof(limb_type))
      result = static_cast<limb_type>(0u);
   else
   {
      unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
      std::memmove(pc + bytes, pc, len);
      std::memset(pc, 0, bytes);
   }
}

template <class Int>
inline void left_shift_limb(Int& result, double_limb_type s)
{
   limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
   limb_type shift = static_cast<limb_type>(s % Int::limb_bits);

   unsigned ors = result.size();
   if((ors == 1) && (!*result.limbs()))
      return; // shifting zero yields zero.
   unsigned rs = ors;
   if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
      ++rs; // Most significant limb will overflow when shifted
   rs += offset;
   result.resize(rs, rs);

   typename Int::limb_pointer pr = result.limbs();

   if(offset > rs)
   {
      // The result is shifted past the end of the result:
      result = static_cast<limb_type>(0);
      return;
   }

   unsigned i = rs - result.size();
   for(; i < ors; ++i)
      pr[rs - 1 - i] = pr[ors - 1 - i];
   for(; i < rs; ++i)
      pr[rs - 1 - i] = 0;
}

template <class Int>
inline void left_shift_generic(Int& result, double_limb_type s)
{
   limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
   limb_type shift = static_cast<limb_type>(s % Int::limb_bits);

   unsigned ors = result.size();
   if((ors == 1) && (!*result.limbs()))
      return; // shifting zero yields zero.
   unsigned rs = ors;
   if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
      ++rs; // Most significant limb will overflow when shifted
   rs += offset;
   result.resize(rs, rs);
   bool truncated = result.size() != rs;

   typename Int::limb_pointer pr = result.limbs();

   if(offset > rs)
   {
      // The result is shifted past the end of the result:
      result = static_cast<limb_type>(0);
      return;
   }

   unsigned i = rs - result.size();
   // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
   BOOST_ASSERT(shift);
   if(!truncated)
   {
      if(rs > ors + offset)
      {
         pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
         --rs;
      }
      else
      {
         pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
         if(ors > 1)
            pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
         ++i;
      }
   }
   for(; ors > 1 + i; ++i)
   {
      pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
      pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
   }
   if(ors >= 1 + i)
   {
      pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
      ++i;
   }
   for(; i < rs; ++i)
      pr[rs - 1 - i] = 0;
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
   eval_left_shift(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
   if(!s)
      return;

#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
   static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
   static const limb_type byte_shift_mask = CHAR_BIT - 1;
   if((s & limb_shift_mask) == 0)
   {
      left_shift_limb(result, s);
   }
   else if((s & byte_shift_mask) == 0)
   {
      left_shift_byte(result, s);
   }
#elif defined(BOOST_LITTLE_ENDIAN)
   static const limb_type byte_shift_mask = CHAR_BIT - 1;
   if((s & byte_shift_mask) == 0)
   {
      left_shift_byte(result, s);
   }
#else
   static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
   if((s & limb_shift_mask) == 0)
   {
      left_shift_limb(result, s);
   }
#endif
   else
   {
      left_shift_generic(result, s);
   }
   //
   // We may have shifted off the end and have leading zeros:
   //
   result.normalize();
}

template <class Int>
inline void right_shift_byte(Int& result, double_limb_type s)
{
   limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
   limb_type shift;
   BOOST_ASSERT((s % CHAR_BIT) == 0);
   unsigned ors = result.size();
   unsigned rs = ors;
   if(offset >= rs)
   {
      result = limb_type(0);
      return;
   }
   rs -= offset;
   typename Int::limb_pointer pr = result.limbs();
   unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
   shift = static_cast<limb_type>(s / CHAR_BIT);
   std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift);
   shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT;
   if(shift < Int::limb_bits)
   {
      pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
      if(!pr[ors - offset - 1] && (rs > 1))
         --rs;
   }
   result.resize(rs, rs);
}

template <class Int>
inline void right_shift_limb(Int& result, double_limb_type s)
{
   limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
   BOOST_ASSERT((s % Int::limb_bits) == 0);
   unsigned ors = result.size();
   unsigned rs = ors;
   if(offset >= rs)
   {
      result = limb_type(0);
      return;
   }
   rs -= offset;
   typename Int::limb_pointer pr = result.limbs();
   unsigned i = 0;
   for(; i < rs; ++i)
      pr[i] = pr[i + offset];
   result.resize(rs, rs);
}

template <class Int>
inline void right_shift_generic(Int& result, double_limb_type s)
{
   limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
   limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
   unsigned ors = result.size();
   unsigned rs = ors;
   if(offset >= rs)
   {
      result = limb_type(0);
      return;
   }
   rs -= offset;
   typename Int::limb_pointer pr = result.limbs();
   if((pr[ors - 1] >> shift) == 0)
   {
      if(--rs == 0)
      {
         result = limb_type(0);
         return;
      }
   }
   unsigned i = 0;

   // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
   BOOST_ASSERT(shift);
   for(; i + offset + 1 < ors; ++i)
   {
      pr[i] = pr[i + offset] >> shift;
      pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
   }
   pr[i] = pr[i + offset] >> shift;
   result.resize(rs, rs);
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
   eval_right_shift(
      cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
      double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
   if(!s)
      return;

#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
   static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
   static const limb_type byte_shift_mask = CHAR_BIT - 1;
   if((s & limb_shift_mask) == 0)
      right_shift_limb(result, s);
   else if((s & byte_shift_mask) == 0)
      right_shift_byte(result, s);
#elif defined(BOOST_LITTLE_ENDIAN)
   static const limb_type byte_shift_mask = CHAR_BIT - 1;
   if((s & byte_shift_mask) == 0)
      right_shift_byte(result, s);
#else
   static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
   if((s & limb_shift_mask) == 0)
      right_shift_limb(result, s);
#endif
   else
      right_shift_generic(result, s);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type
   eval_right_shift(
      cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result,
      double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
   if(!s)
      return;

   bool is_neg = result.sign();
   if(is_neg)
      eval_increment(result);

#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
   static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
   static const limb_type byte_shift_mask = CHAR_BIT - 1;
   if((s & limb_shift_mask) == 0)
      right_shift_limb(result, s);
   else if((s & byte_shift_mask) == 0)
      right_shift_byte(result, s);
#elif defined(BOOST_LITTLE_ENDIAN)
   static const limb_type byte_shift_mask = CHAR_BIT - 1;
   if((s & byte_shift_mask) == 0)
      right_shift_byte(result, s);
#else
   static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
   if((s & limb_shift_mask) == 0)
      right_shift_limb(result, s);
#endif
   else
      right_shift_generic(result, s);
   if(is_neg)
      eval_decrement(result);
}

//
// Over again for trivial cpp_int's:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
   eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
   *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
   result.normalize();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
   eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   // Nothing to check here... just make sure we don't invoke undefined behavior:
   is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
   *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s);
   if(result.sign() && (*result.limbs() == 0))
      result = static_cast<signed_limb_type>(-1);
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
         >::type
   eval_complement(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
   //
   // If we're not checked then emulate 2's complement behavior:
   //
   if(o.sign())
   {
      *result.limbs() = *o.limbs() - 1;
      result.sign(false);
   }
   else
   {
      *result.limbs() = 1 + *o.limbs();
      result.sign(true);
   }
   result.normalize();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         >::type
   eval_complement(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   *result.limbs() = ~*o.limbs();
   result.normalize();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         >::type
   eval_bitwise_and(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   *result.limbs() &= *o.limbs();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
         >::type
   eval_bitwise_and(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());

   using default_ops::eval_bit_test;
   using default_ops::eval_increment;

   if(result.sign() || o.sign())
   {
      static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
      cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
      cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
      eval_bitwise_and(t1, t2);
      bool s = eval_bit_test(t1, m + 1);
      if(s)
      {
         eval_complement(t1, t1);
         eval_increment(t1);
      }
      result = t1;
      result.sign(s);
   }
   else
   {
      *result.limbs() &= *o.limbs();
   }
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         >::type
   eval_bitwise_or(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   *result.limbs() |= *o.limbs();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
         >::type
   eval_bitwise_or(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());

   using default_ops::eval_bit_test;
   using default_ops::eval_increment;

   if(result.sign() || o.sign())
   {
      static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
      cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
      cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
      eval_bitwise_or(t1, t2);
      bool s = eval_bit_test(t1, m + 1);
      if(s)
      {
         eval_complement(t1, t1);
         eval_increment(t1);
      }
      result = t1;
      result.sign(s);
   }
   else
   {
      *result.limbs() |= *o.limbs();
      result.normalize();
   }
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         >::type
   eval_bitwise_xor(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   *result.limbs() ^= *o.limbs();
}

template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
inline typename enable_if_c<
         is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
         && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
         && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
         >::type
   eval_bitwise_xor(
      cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
      const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
   is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());

   using default_ops::eval_bit_test;
   using default_ops::eval_increment;

   if(result.sign() || o.sign())
   {
      static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
      cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
      cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
      eval_bitwise_xor(t1, t2);
      bool s = eval_bit_test(t1, m + 1);
      if(s)
      {
         eval_complement(t1, t1);
         eval_increment(t1);
      }
      result = t1;
      result.sign(s);
   }
   else
   {
      *result.limbs() ^= *o.limbs();
   }
}

}}} // namespaces

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif


<?php

namespace EventEspresso\core\domain\entities\shortcodes;

use DomainException;
use EE_Datetime;
use EE_Error;
use EE_Event;
use EE_Ticket;
use EEH_Event_View;
use EEH_Template;
use EEM_Attendee;
use EEM_Datetime;
use EEM_Event;
use EEM_Registration;
use EEM_Ticket;
use EventEspresso\core\exceptions\EntityNotFoundException;
use EventEspresso\core\exceptions\InvalidDataTypeException;
use EventEspresso\core\exceptions\InvalidInterfaceException;
use EventEspresso\core\services\shortcodes\EspressoShortcode;
use InvalidArgumentException;

/**
 * Class EspressoEventAttendees
 * ESPRESSO_EVENT_ATTENDEES shortcode
 *
 * @package Event Espresso
 * @author  Darren Ethier
 * @since   4.9.26
 */
class EspressoEventAttendees extends EspressoShortcode
{

    private $query_params = array(
        0 => array(),
    );

    private $template_args = array(
        'contacts' => array(),
        'event'    => null,
        'datetime' => null,
        'ticket'   => null,
    );

    /**
     * the actual shortcode tag that gets registered with WordPress
     *
     * @return string
     */
    public function getTag()
    {
        return 'ESPRESSO_EVENT_ATTENDEES';
    }

    /**
     * the time in seconds to cache the results of the processShortcode() method
     * 0 means the processShortcode() results will NOT be cached at all
     *
     * @return int
     */
    public function cacheExpiration()
    {
        return 0;
    }

    /**
     * a place for adding any initialization code that needs to run prior to wp_header().
     * this may be required for shortcodes that utilize a corresponding module,
     * and need to enqueue assets for that module
     *
     * @return void
     */
    public function initializeShortcode()
    {
        $this->shortcodeHasBeenInitialized();
    }

    /**
     * process_shortcode - ESPRESSO_EVENT_ATTENDEES - Returns a list of attendees to an event.
     *  [ESPRESSO_EVENT_ATTENDEES]
     *  - defaults to attendees for earliest active event, or earliest upcoming event.
     *  [ESPRESSO_EVENT_ATTENDEES event_id=123]
     *  - attendees for specific event.
     *  [ESPRESSO_EVENT_ATTENDEES datetime_id=245]
     *  - attendees for a specific datetime.
     *  [ESPRESSO_EVENT_ATTENDEES ticket_id=123]
     *  - attendees for a specific ticket.
     *  [ESPRESSO_EVENT_ATTENDEES status=all]
     *  - specific registration status (use status id) or all for all attendees regardless of status.
     *  Note default is to only return approved attendees
     *  [ESPRESSO_EVENT_ATTENDEES show_gravatar=true]
     *  - default is to not return gravatar.  Otherwise if this is set then return gravatar for email address given.
     *  [ESPRESSO_EVENT_ATTENDEES display_on_archives=true]
     *  - default is to not display attendees list on archive pages.
     * Note: because of the relationship between event_id, ticket_id, and datetime_id:
     * If more than one of those params is included, then preference is given to the following:
     *  - event_id is used whenever its present and any others are ignored.
     *  - if no event_id then datetime is used whenever its present and any others are ignored.
     *  - otherwise ticket_id is used if present.
     *
     * @param array $attributes
     * @return string
     * @throws EE_Error
     * @throws InvalidDataTypeException
     * @throws InvalidInterfaceException
     * @throws InvalidArgumentException
     * @throws DomainException
     */
    public function processShortcode($attributes = array())
    {
        // grab attributes and merge with defaults
        $attributes = $this->getAttributes((array) $attributes);
        $attributes['limit'] = (int) $attributes['limit'];
        $display_on_archives = filter_var($attributes['display_on_archives'], FILTER_VALIDATE_BOOLEAN);
        // don't display on archives unless 'display_on_archives' is true
        if ($attributes['limit'] === 0 || (! $display_on_archives && is_archive())) {
            return '';
        }
        try {
            $this->setBaseTemplateArguments($attributes);
            $this->validateEntities($attributes);
            $this->setBaseQueryParams();
        } catch (EntityNotFoundException $e) {
            if (WP_DEBUG) {
                return '
'
                       . $e->getMessage()
                       . '
';
            }
            return '';
        }
        $this->setAdditionalQueryParams($attributes);
        // get contacts!
        $this->template_args['contacts'] = EEM_Attendee::instance()->get_all($this->query_params);
        // all set let's load up the template and return.
        return EEH_Template::locate_template(
            'loop-espresso_event_attendees.php',
            $this->template_args
        );
    }

    /**
     * merge incoming attributes with filtered defaults
     *
     * @param array $attributes
     * @return array
     */
    private function getAttributes(array $attributes)
    {
        return (array) apply_filters(
            'EES_Espresso_Event_Attendees__process_shortcode__default_shortcode_atts',
            $attributes + array(
                'event_id'            => null,
                'datetime_id'         => null,
                'ticket_id'           => null,
                'status'              => EEM_Registration::status_id_approved,
                'show_gravatar'       => false,
                'display_on_archives' => false,
                'limit'               => 999,
            )
        );
    }

    /**
     * Set all the base template arguments from the incoming attributes.
     * * Note: because of the relationship between event_id, ticket_id, and datetime_id:
     * If more than one of those params is included, then preference is given to the following:
     *  - event_id is used whenever its present and any others are ignored.
     *  - if no event_id then datetime is used whenever its present and any others are ignored.
     *  - otherwise ticket_id is used if present.
     *
     * @param array $attributes
     * @throws EE_Error
     * @throws InvalidDataTypeException
     * @throws InvalidInterfaceException
     * @throws InvalidArgumentException
     */
    private function setBaseTemplateArguments(array $attributes)
    {
        $this->template_args['show_gravatar'] = $attributes['show_gravatar'];
        $this->template_args['event'] = $this->getEvent($attributes);
        $this->template_args['datetime'] = empty($attributes['event_id'])
            ? $this->getDatetime($attributes)
            : null;
        $this->template_args['ticket'] = empty($attributes['datetime_id']) && empty($attributes['event_id'])
            ? $this->getTicket($attributes)
            : null;
    }

    /**
     * Validates the presence of entities for the given attribute values.
     *
     * @param array $attributes
     * @throws EntityNotFoundException
     */
    private function validateEntities(array $attributes)
    {
        if (! $this->template_args['event'] instanceof EE_Event
            || (
                empty($attributes['event_id'])
                && $attributes['datetime_id']
                && ! $this->template_args['datetime'] instanceof EE_Datetime
            )
            || (
                empty($attributes['event_id'])
                && empty($attributes['datetime_id'])
                && $attributes['ticket_id']
                && ! $this->template_args['ticket'] instanceof EE_Ticket
            )
        ) {
            throw new EntityNotFoundException(
                '',
                '',
                esc_html__(
                    'The [ESPRESSO_EVENT_ATTENDEES] shortcode has been used incorrectly.  Please double check the arguments you used for any typos.  In the case of ID type arguments, its possible the given ID does not correspond to existing data in the database.',
                    'event_espresso'
                )
            );
        }
    }

    /**
     * Sets the query params for the base query elements.
     */
    private function setBaseQueryParams()
    {
        switch (true) {
            case $this->template_args['datetime'] instanceof EE_Datetime:
                $this->query_params = array(
                    0                          => array(
                        'Registration.Ticket.Datetime.DTT_ID' => $this->template_args['datetime']->ID(),
                    ),
                    'default_where_conditions' => 'this_model_only',
                );
                break;
            case $this->template_args['ticket'] instanceof EE_Ticket:
                $this->query_params[0] = array(
                    'Registration.TKT_ID' => $this->template_args['ticket']->ID(),
                );
                break;
            case $this->template_args['event'] instanceof EE_Event:
                $this->query_params[0] = array(
                    'Registration.EVT_ID' => $this->template_args['event']->ID(),
                );
                break;
        }
    }

    /**
     * @param array $attributes
     * @return EE_Event|null
     * @throws EE_Error
     * @throws InvalidDataTypeException
     * @throws InvalidInterfaceException
     * @throws InvalidArgumentException
     */
    private function getEvent(array $attributes)
    {
        switch (true) {
            case ! empty($attributes['event_id']):
                $event = EEM_Event::instance()->get_one_by_ID($attributes['event_id']);
                break;
            case ! empty($attributes['datetime_id']):
                $event = EEM_Event::instance()->get_one(array(
                    array(
                        'Datetime.DTT_ID' => $attributes['datetime_id'],
                    ),
                ));
                break;
            case ! empty($attributes['ticket_id']):
                $event = EEM_Event::instance()->get_one(array(
                    array(
                        'Datetime.Ticket.TKT_ID' => $attributes['ticket_id'],
                    ),
                    'default_where_conditions' => 'none'
                ));
                break;
            case is_espresso_event():
                $event = EEH_Event_View::get_event();
                break;
            default:
                // one last shot...
                // try getting the earliest active event
                $events = EEM_Event::instance()->get_active_events(array(
                    'limit'    => 1,
                    'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'),
                ));
                //  if none then get the next upcoming
                $events = empty($events)
                    ? EEM_Event::instance()->get_upcoming_events(array(
                        'limit'    => 1,
                        'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'),
                    ))
                    : $events;
                $event = reset($events);
        }

        return $event instanceof EE_Event ? $event : null;
    }

    /**
     * @param array $attributes
     * @return EE_Datetime|null
     * @throws EE_Error
     * @throws InvalidDataTypeException
     * @throws InvalidInterfaceException
     * @throws InvalidArgumentException
     */
    private function getDatetime(array $attributes)
    {
        if (! empty($attributes['datetime_id'])) {
            $datetime = EEM_Datetime::instance()->get_one_by_ID($attributes['datetime_id']);
            if ($datetime instanceof EE_Datetime) {
                return $datetime;
            }
        }
        return null;
    }

    /**
     * @param array $attributes
     * @return \EE_Base_Class|EE_Ticket|null
     * @throws EE_Error
     * @throws InvalidDataTypeException
     * @throws InvalidInterfaceException
     * @throws InvalidArgumentException
     */
    private function getTicket(array $attributes)
    {
        if (! empty($attributes['ticket_id'])) {
            $ticket = EEM_Ticket::instance()->get_one_by_ID($attributes['ticket_id']);
            if ($ticket instanceof EE_Ticket) {
                return $ticket;
            }
        }
        return null;
    }

    /**
     * @param array $attributes
     * @throws EE_Error
     */
    private function setAdditionalQueryParams(array $attributes)
    {
        $reg_status_array = EEM_Registration::reg_status_array();
        if (isset($reg_status_array[ $attributes['status'] ])) {
            $this->query_params[0]['Registration.STS_ID'] = $attributes['status'];
        }
        if (absint($attributes['limit'])) {
            $this->query_params['limit'] = $attributes['limit'];
        }
        $this->query_params['group_by'] = array('ATT_ID');
        $this->query_params['order_by'] = (array) apply_filters(
            'FHEE__EES_Espresso_Event_Attendees__process_shortcode__order_by',
            array('ATT_lname' => 'ASC', 'ATT_fname' => 'ASC')
        );
    }
}


/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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

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

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

import {baseUrl} from "./utils/permalinks/SpecPermalinkConstructor";
import {
    parsePermalink,
    tryTransformEntityToPermalink,
    tryTransformPermalinkToLocalHref,
} from "./utils/permalinks/Permalinks";

function matrixLinkify(linkify) {
    // Text tokens
    const TT = linkify.scanner.TOKENS;
    // Multi tokens
    const MT = linkify.parser.TOKENS;
    const MultiToken = MT.Base;
    const S_START = linkify.parser.start;

    if (TT.UNDERSCORE === undefined) {
        throw new Error("linkify-matrix requires linkifyjs 2.1.1: this version is too old.");
    }

    const ROOMALIAS = function(value) {
        MultiToken.call(this, value);
        this.type = 'roomalias';
        this.isLink = true;
    };
    ROOMALIAS.prototype = new MultiToken();

    const S_HASH = S_START.jump(TT.POUND);
    const S_HASH_NAME = new linkify.parser.State();
    const S_HASH_NAME_COLON = new linkify.parser.State();
    const S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State(ROOMALIAS);
    const S_HASH_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_ROOMALIAS = new linkify.parser.State(ROOMALIAS);
    const S_ROOMALIAS_COLON = new linkify.parser.State();
    const S_ROOMALIAS_COLON_NUM = new linkify.parser.State(ROOMALIAS);

    const roomnameTokens = [
        TT.DOT,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,
        TT.UNDERSCORE,
        TT.POUND,

        // because 'localhost' is tokenised to the localhost token,
        // usernames @localhost:foo.com are otherwise not matched!
        TT.LOCALHOST,
    ];

    S_HASH.on(roomnameTokens, S_HASH_NAME);
    S_HASH_NAME.on(roomnameTokens, S_HASH_NAME);
    S_HASH_NAME.on(TT.DOMAIN, S_HASH_NAME);

    S_HASH_NAME.on(TT.COLON, S_HASH_NAME_COLON);

    S_HASH_NAME_COLON.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
    S_HASH_NAME_COLON.on(TT.LOCALHOST, S_ROOMALIAS); // accept #foo:localhost
    S_HASH_NAME_COLON.on(TT.TLD, S_ROOMALIAS); // accept #foo:com (mostly for (TLD|DOMAIN)+ mixing)
    S_HASH_NAME_COLON_DOMAIN.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT);
    S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
    S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_ROOMALIAS);

    S_ROOMALIAS.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk)
    S_ROOMALIAS.on(TT.COLON, S_ROOMALIAS_COLON); // do not accept trailing `:`
    S_ROOMALIAS_COLON.on(TT.NUM, S_ROOMALIAS_COLON_NUM); // but do accept :NUM (port specifier)

    const USERID = function(value) {
        MultiToken.call(this, value);
        this.type = 'userid';
        this.isLink = true;
    };
    USERID.prototype = new MultiToken();

    const S_AT = S_START.jump(TT.AT);
    const S_AT_NAME = new linkify.parser.State();
    const S_AT_NAME_COLON = new linkify.parser.State();
    const S_AT_NAME_COLON_DOMAIN = new linkify.parser.State(USERID);
    const S_AT_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_USERID = new linkify.parser.State(USERID);
    const S_USERID_COLON = new linkify.parser.State();
    const S_USERID_COLON_NUM = new linkify.parser.State(USERID);

    const usernameTokens = [
        TT.DOT,
        TT.UNDERSCORE,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,

        // as in roomnameTokens
        TT.LOCALHOST,
    ];

    S_AT.on(usernameTokens, S_AT_NAME);
    S_AT_NAME.on(usernameTokens, S_AT_NAME);
    S_AT_NAME.on(TT.DOMAIN, S_AT_NAME);

    S_AT_NAME.on(TT.COLON, S_AT_NAME_COLON);

    S_AT_NAME_COLON.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
    S_AT_NAME_COLON.on(TT.LOCALHOST, S_USERID); // accept @foo:localhost
    S_AT_NAME_COLON.on(TT.TLD, S_USERID); // accept @foo:com (mostly for (TLD|DOMAIN)+ mixing)
    S_AT_NAME_COLON_DOMAIN.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT);
    S_AT_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
    S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID);

    S_USERID.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk)
    S_USERID.on(TT.COLON, S_USERID_COLON); // do not accept trailing `:`
    S_USERID_COLON.on(TT.NUM, S_USERID_COLON_NUM); // but do accept :NUM (port specifier)

    const GROUPID = function(value) {
        MultiToken.call(this, value);
        this.type = 'groupid';
        this.isLink = true;
    };
    GROUPID.prototype = new MultiToken();

    const S_PLUS = S_START.jump(TT.PLUS);
    const S_PLUS_NAME = new linkify.parser.State();
    const S_PLUS_NAME_COLON = new linkify.parser.State();
    const S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State(GROUPID);
    const S_PLUS_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_GROUPID = new linkify.parser.State(GROUPID);
    const S_GROUPID_COLON = new linkify.parser.State();
    const S_GROUPID_COLON_NUM = new linkify.parser.State(GROUPID);

    const groupIdTokens = [
        TT.DOT,
        TT.UNDERSCORE,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,

        // as in roomnameTokens
        TT.LOCALHOST,
    ];

    S_PLUS.on(groupIdTokens, S_PLUS_NAME);
    S_PLUS_NAME.on(groupIdTokens, S_PLUS_NAME);
    S_PLUS_NAME.on(TT.DOMAIN, S_PLUS_NAME);

    S_PLUS_NAME.on(TT.COLON, S_PLUS_NAME_COLON);

    S_PLUS_NAME_COLON.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
    S_PLUS_NAME_COLON.on(TT.LOCALHOST, S_GROUPID); // accept +foo:localhost
    S_PLUS_NAME_COLON.on(TT.TLD, S_GROUPID); // accept +foo:com (mostly for (TLD|DOMAIN)+ mixing)
    S_PLUS_NAME_COLON_DOMAIN.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT);
    S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
    S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_GROUPID);

    S_GROUPID.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk)
    S_GROUPID.on(TT.COLON, S_GROUPID_COLON); // do not accept trailing `:`
    S_GROUPID_COLON.on(TT.NUM, S_GROUPID_COLON_NUM); // but do accept :NUM (port specifier)
}

// stubs, overwritten in MatrixChat's componentDidMount
matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); };
matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); };
matrixLinkify.onGroupClick = function(e, groupId) { e.preventDefault(); };

const escapeRegExp = function(string) {
    return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};

// Recognise URLs from both our local vector and official vector as vector.
// anyone else really should be using matrix.to.
matrixLinkify.VECTOR_URL_PATTERN = "^(?:https?://)?(?:"
    + escapeRegExp(window.location.host + window.location.pathname) + "|"
    + "(?:www\\.)?(?:riot|vector)\\.im/(?:app|beta|staging|develop)/"
    + ")(#.*)";

matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?://)?(?:www\\.)?matrix\\.to/#/(([#@!+]).*)";
matrixLinkify.MATRIXTO_MD_LINK_PATTERN =
    '\\[([^\\]]*)\\]\\((?:https?://)?(?:www\\.)?matrix\\.to/#/([#@!+][^\\)]*)\\)';
matrixLinkify.MATRIXTO_BASE_URL= baseUrl;

matrixLinkify.options = {
    events: function(href, type) {
        switch (type) {
            case "url": {
                // intercept local permalinks to users and show them like userids (in userinfo of current room)
                try {
                    const permalink = parsePermalink(href);
                    if (permalink && permalink.userId) {
                        return {
                            click: function(e) {
                                matrixLinkify.onUserClick(e, permalink.userId);
                            },
                        };
                    }
                } catch (e) {
                    // OK fine, it's not actually a permalink
                }
                break;
            }
            case "userid":
                return {
                    click: function(e) {
                        matrixLinkify.onUserClick(e, href);
                    },
                };
            case "roomalias":
                return {
                    click: function(e) {
                        matrixLinkify.onAliasClick(e, href);
                    },
                };
            case "groupid":
                return {
                    click: function(e) {
                        matrixLinkify.onGroupClick(e, href);
                    },
                };
        }
    },

    formatHref: function(href, type) {
        switch (type) {
            case 'roomalias':
            case 'userid':
            case 'groupid':
            default: {
                return tryTransformEntityToPermalink(href);
            }
        }
    },

    linkAttributes: {
        rel: 'noreferrer noopener',
    },

    target: function(href, type) {
        if (type === 'url') {
            const transformed = tryTransformPermalinkToLocalHref(href);
            if (transformed !== href || href.match(matrixLinkify.VECTOR_URL_PATTERN)) {
                return null;
            } else {
                return '_blank';
            }
        }
        return null;
    },
};

export default matrixLinkify;


; RUN: opt < %s -instcombine -S | FileCheck %s

define zeroext i1 @_Z3fooPb(i8* nocapture %x) {
entry:
  %a = load i8, i8* %x, align 1, !range !0
  %b = and i8 %a, 1
  %tobool = icmp ne i8 %b, 0
  ret i1 %tobool
}

; CHECK: %a = load i8, i8* %x, align 1, !range !0
; CHECK-NEXT: %tobool = icmp ne i8 %a, 0
; CHECK-NEXT: ret i1 %tobool

!0 = !{i8 0, i8 2}


//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

// platformSemaphore.h does not ask for any inter process communication,
// and the posix semaphores require a file to be created on disk.
// which could create annoyances if the appication crashes...
// so we'll just roll our own semaphore here.

// note: this is not a bulletproof solution to the starving problem...
// see: The Little Book of Semapores, by Allen B. Downey, at http://greenteapress.com/semaphores/

#include <pthread.h>
#include "platform/platform.h"
#include "platform/threads/semaphore.h"

struct PlatformSemaphore
{
   pthread_mutex_t mDarkroom;
//   pthread_mutex_t mFoyer; // second lock, to help control starving.
   pthread_cond_t  mCond;
   S32 count;
};

Semaphore::Semaphore(S32 initialCount)
{
   bool ok;
   PlatformSemaphore* semaphore = new PlatformSemaphore();
   ok = pthread_mutex_init(&semaphore->mDarkroom,NULL);
   AssertFatal(ok == 0,"Create semaphore failed at creating mutex mDarkroom.");
//   ok = pthread_mutex_init(&semaphore->mFoyer,NULL);
//   AssertFatal(ok != 0,"Create semaphore failed at creating mutex mFoyer.");
   ok = pthread_cond_init(&semaphore->mCond,NULL);
   AssertFatal(ok == 0,"Create semaphore failed at creating condition mCond.");

   semaphore->count = initialCount;
   mData = semaphore;
}

Semaphore::~Semaphore()
{
   pthread_mutex_destroy(&mData->mDarkroom);
//   pthread_mutex_destroy(&mData->mFoyer);
   pthread_cond_destroy(&mData->mCond);

   delete mData;
}

bool Semaphore::acquire( bool block, S32 timeoutMS )
{

   bool ok;
   AssertFatal(mData, "Semaphore::acquireSemaphore: invalid semaphore");

   ok = pthread_mutex_lock(&mData->mDarkroom);
   AssertFatal(ok == 0,"Mutex Lock failed on mDarkroom in acquireSemaphore().");

   if(mData->count <= 0 && !block) {
      ok = pthread_mutex_unlock(&mData->mDarkroom);
      AssertFatal(ok == 0,"Mutex Unlock failed on mDarkroom when not blocking in acquireSemaphore().");
      return false;
   }

   while( mData->count <= 0 )
   {
      ok = pthread_cond_wait(&mData->mCond, &mData->mDarkroom); // releases mDarkroom while blocked.
      AssertFatal(ok == 0,"Waiting on mCond failed in acquireSemaphore().");
   }

   mData->count--;

   ok = pthread_mutex_unlock(&mData->mDarkroom);
   AssertFatal(ok == 0,"Mutex Unlock failed on mDarkroom when leaving acquireSemaphore().");

   return true;
}

void Semaphore::release()
{
   bool ok;
   AssertFatal(mData, "Semaphore::releaseSemaphore: invalid semaphore");

   ok = pthread_mutex_lock(&mData->mDarkroom);
   AssertFatal(ok == 0,"Mutex Lock failed on mDarkroom in releaseSemaphore().");

   mData->count++;
   if(mData->count > 0) {
      ok = pthread_cond_signal(&mData->mCond);
      AssertFatal(ok == 0,"Signaling mCond failed in releaseSemaphore().");
   }

   ok = pthread_mutex_unlock(&mData->mDarkroom);
    AssertFatal(ok == 0,"Mutex Unlock failed on mDarkroom when leaving releaseSemaphore().");
}


# Gleaming Loading
 _A Pen created at CodePen.io. Original URL: [https://codepen.io/alphardex/pen/QWLYVjV](https://codepen.io/alphardex/pen/QWLYVjV).


#ifndef __CWIKICACHE_BI__
#define __CWIKICACHE_BI__

''  fbdoc - FreeBASIC User's Manual Converter/Generator
''	Copyright (C) 2006-2020 The FreeBASIC development team.
''
''	This program is free software; you can redistribute it and/or modify
''	it under the terms of the GNU General Public License as published by
''	the Free Software Foundation; either version 2 of the License, or
''	(at your option) any later version.
''
''	This program is distributed in the hope that it will be useful,
''	but WITHOUT ANY WARRANTY; without even the implied warranty of
''	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
''	GNU General Public License for more details.
''
''	You should have received a copy of the GNU General Public License
''	along with this program; if not, write to the Free Software
''	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301 USA.

#include once "fbdoc_defs.bi"

namespace fb.fbdoc

	type CWikiCacheCtx as CWikiCacheCtx_

	type CWikiCache

		enum CACHE_REFRESH_MODE
			CACHE_REFRESH_NONE
			CACHE_REFRESH_IFMISSING
			CACHE_REFRESH_ALL
		end enum

		declare constructor _
			( _
				byval localdir as zstring ptr, _
				byval bRefresh as integer = FALSE _
			)

		declare destructor _
			( _
			)

		declare function LoadPage _
			( _
				byval sPage as zstring ptr, _
				byref sBody as string _
			) as integer

		declare function SavePage _
			( _
				byval sPage as zstring ptr, _
				byval sBody as zstring ptr _
			) as integer

		declare function GetRefreshMode _
			( _
			) as integer

		declare function SetRefreshMode _
			( _
				byval RefreshMode as integer _
			) as integer

		ctx as CWikiCacheCtx ptr

	end type

end namespace

#endif


/**
 * A specialized version of `_.reduce` for arrays without support for
 * iteratee shorthands.
 *
 * @private
 * @param {Array} [array] The array to iterate over.
 * @param {Function} iteratee The function invoked per iteration.
 * @param {*} [accumulator] The initial value.
 * @param {boolean} [initAccum] Specify using the first element of `array` as
 *  the initial value.
 * @returns {*} Returns the accumulated value.
 */
function arrayReduce(array, iteratee, accumulator, initAccum) {
  var index = -1,
      length = array == null ? 0 : array.length;

  if (initAccum && length) {
    accumulator = array[++index];
  }
  while (++index < length) {
    accumulator = iteratee(accumulator, array[index], index, array);
  }
  return accumulator;
}

module.exports = arrayReduce;


<% unless @work_logs.empty? %>

      <%= link_to "PDF", current_url(:format => :pdf), :target => "_blank" %>
      <%= link_to "CSV", current_url(:format => :csv), :target => "_blank" %>
      <%= link_to "Excel", current_url(:format => :xls), :target => "_blank" %>

        Date
        Total hours
        Total hours
        Total hours
        Description

      <% @work_logs.each do |log| %>

            <%= log.date.strftime('%d %B %Y') %>
            <%= log.hours.gsub(":","") %>
            <%= log.hours %>
            <%= log.hours.gsub(":",",") %>
            <%= log.description %>

      <% end %>

<% else %>

      No sufficient data yet.

<% end %>


.b-progress-wrapper {
  border: 1px solid #111;
  border-radius: 2px;
  overflow: hidden;
  position: relative;
  height: 30px;
  width: 100%;
}
.b-progress-wrapper[data-progress]::before {
  color: #fff;
  content: attr(data-progress);
  line-height: 30px;
  padding-left: 10px;
  position: relative;
  text-align: left;
  z-index: 1;
}
.b-progress {
  background: #111;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
}
.b-progress-indeterminate {
  background: #111;
  border-color: #111;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  animation: interdeterminate-progress-bar 2.5s ease-in-out alternate infinite;
}
.b-progress-indeterminate ~ .b-progress-label {
  color: #fff;
}
@-moz-keyframes interdeterminate-progress-bar {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@-webkit-keyframes interdeterminate-progress-bar {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@-o-keyframes interdeterminate-progress-bar {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes interdeterminate-progress-bar {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInBhY2thZ2VzL2JvdW5kbGVzcy1wcm9ncmVzcy9zdHlsZS5zdHlsIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBO0VBQ0ksUUFBUSxlQUFSO0VBQ0EsZUFBZSxJQUFmO0VBQ0EsVUFBVSxPQUFWO0VBQ0EsVUFBVSxTQUFWO0VBQ0EsUUFBUSxLQUFSO0VBQ0EsT0FBTyxLQUFQOztBQUdKO0VBQ0ksT0FBTyxLQUFQO0VBQ0EsU0FBMkIsb0JBQTNCO0VBQ0EsYUFBYSxLQUFiO0VBQ0EsY0FBYyxLQUFkO0VBQ0EsVUFBVSxTQUFWO0VBQ0EsWUFBWSxLQUFaO0VBQ0EsU0FBUyxFQUFUOztBQUdKO0VBQ0ksWUFBWSxLQUFaO0VBQ0EsVUFBVSxTQUFWO0VBQ0EsS0FBSyxFQUFMO0VBQ0EsTUFBTSxFQUFOO0VBQ0EsUUFBUSxFQUFSOztBQVFKO0VBQ0ksWUFBWSxLQUFaO0VBQ0EsY0FBYyxLQUFkO0VBQ0EsS0FBSyxFQUFMO0VBQ0EsTUFBTSxFQUFOO0VBQ0EsUUFBUSxFQUFSO0VBQ0EsT0FBTyxFQUFQO0VBQ0EsV0FBVyxrRUFBWDs7QUFFQTtFQUNJLE9BQU8sS0FBUDs7QUFmZ0M7QUFDcEM7SUFBTyxTQUFTLEVBQVQ7O0FBQ1A7SUFBSyxTQUFTLEVBQVQ7OztBQUYrQjtBQUNwQztJQUFPLFNBQVMsRUFBVDs7QUFDUDtJQUFLLFNBQVMsRUFBVDs7O0FBRitCO0FBQ3BDO0lBQU8sU0FBUyxFQUFUOztBQUNQO0lBQUssU0FBUyxFQUFUOzs7QUFGK0I7QUFDcEM7SUFBTyxTQUFTLEVBQVQ7O0FBQ1A7SUFBSyxTQUFTLEVBQVQiLCJmaWxlIjoic3R5bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiQHJlcXVpcmUgXCJ2YXJpYWJsZXNcIlxuXG51bmxlc3MgZmxhdC1idWlsZCB7XG4gICAgQHJlcXVpcmUgXCJub2RlX21vZHVsZXMvYm91bmRsZXNzLWJ1dHRvbi9zdHlsZVwiXG59XG5cbi8vIFNraW4tc3BlY2lmaWMgc3R5bGVzIGdvIGhlcmUuIERlbW8tc3BlY2lmaWMgc3R5bGVzIGdvIGluIGRlbW8vc3R5bGUuc3R5bC5cblxuLmItcHJvZ3Jlc3Mtd3JhcHBlciB7XG4gICAgYm9yZGVyOiBQcm9ncmVzcy1ib3JkZXJXaWR0aCBzb2xpZCBQcm9ncmVzcy1ib3JkZXJDb2xvcjtcbiAgICBib3JkZXItcmFkaXVzOiBib3JkZXJSYWRpdXM7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgaGVpZ2h0OiBQcm9ncmVzcy1oZWlnaHQ7XG4gICAgd2lkdGg6IFByb2dyZXNzLXdpZHRoO1xufVxuXG4uYi1wcm9ncmVzcy13cmFwcGVyW2RhdGEtcHJvZ3Jlc3NdOjpiZWZvcmUge1xuICAgIGNvbG9yOiBQcm9ncmVzcy1sYWJlbC1jb2xvcjtcbiAgICBjb250ZW50OiBhdHRyKGRhdGEtcHJvZ3Jlc3MpO1xuICAgIGxpbmUtaGVpZ2h0OiBQcm9ncmVzcy1oZWlnaHQ7XG4gICAgcGFkZGluZy1sZWZ0OiAxMHB4O1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB0ZXh0LWFsaWduOiBsZWZ0O1xuICAgIHotaW5kZXg6IDE7XG59XG5cbi5iLXByb2dyZXNzIHtcbiAgICBiYWNrZ3JvdW5kOiBQcm9ncmVzcy1iYWNrZ3JvdW5kQ29sb3I7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogMDtcbiAgICBsZWZ0OiAwO1xuICAgIGJvdHRvbTogMDtcbn1cblxuQGtleWZyYW1lcyBpbnRlcmRldGVybWluYXRlLXByb2dyZXNzLWJhciB7XG4gICAgZnJvbSB7IG9wYWNpdHk6IDA7IH1cbiAgICB0byB7IG9wYWNpdHk6IDE7IH1cbn1cblxuLmItcHJvZ3Jlc3MtaW5kZXRlcm1pbmF0ZSB7XG4gICAgYmFja2dyb3VuZDogUHJvZ3Jlc3MtYmFja2dyb3VuZENvbG9yLWluZGV0ZXJtaW5hdGU7XG4gICAgYm9yZGVyLWNvbG9yOiBQcm9ncmVzcy1ib3JkZXJDb2xvci1pbmRldGVybWluYXRlO1xuICAgIHRvcDogMDtcbiAgICBsZWZ0OiAwO1xuICAgIGJvdHRvbTogMDtcbiAgICByaWdodDogMDtcbiAgICBhbmltYXRpb246IGludGVyZGV0ZXJtaW5hdGUtcHJvZ3Jlc3MtYmFyIDIuNXMgZWFzZS1pbi1vdXQgYWx0ZXJuYXRlIGluZmluaXRlO1xuXG4gICAgfiAuYi1wcm9ncmVzcy1sYWJlbCB7XG4gICAgICAgIGNvbG9yOiBQcm9ncmVzcy1sYWJlbC1jb2xvci1pbmRldGVybWluYXRlO1xuICAgIH1cbn1cbiJdfQ== */


owner = HOL
controller = HOL
add_core = HOL
add_core = INO

infra = 1

1942.6.4 = {
	controller = JAP
}


/*
 * Wazuh Module for Agent control
 * Copyright (C) 2015-2020, Wazuh Inc.
 * January, 2019
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#if defined (__linux__) || defined (__MACH__) || defined (sun)
#include "wm_control.h"
#include "syscollector/syscollector.h"
#include "external/cJSON/cJSON.h"
#include "file_op.h"
#include "../os_net/os_net.h"

static void *wm_control_main();
static void wm_control_destroy();
cJSON *wm_control_dump();

const wm_context WM_CONTROL_CONTEXT = {
    "control",
    (wm_routine)wm_control_main,
    (wm_routine)(void *)wm_control_destroy,
    (cJSON * (*)(const void *))wm_control_dump
};

#if defined (__linux__) || defined (__MACH__)
#include <ifaddrs.h>
#elif defined sun
#include <net/if.h>
#include <sys/sockio.h>

/**
 * @brief Get the number of available network interfaces
 *
 * @return Number of network interfaces in the system.
 */
static int get_if_num() {
    int fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (fd == -1) {
        return -1;
    }

    struct lifnum ifn = { .lifn_family = AF_INET };

    int retval = ioctl(fd, SIOCGLIFNUM, &ifn);
    close(fd);

    if (retval == -1) {
        return -1;
    }

    return ifn.lifn_count;
}

#endif

/**
 * @brief Get the Primary IP address
 *
 * Resolve the host's IP as the IP address of the default route interface,
 * or the first non-loopback available interface.
 *
 * @return Pointer to a string holding the host's IP.
 * @post The user must free the returned pointer.
 */
char* getPrimaryIP(){
     /* Get Primary IP */
    char * agent_ip = NULL;

#if defined __linux__ || defined __MACH__
    char **ifaces_list;
    struct ifaddrs *ifaddr = NULL, *ifa;
    int size;
    int i = 0;
#ifdef __linux__
    int min_metric = INT_MAX;
#endif

    if (getifaddrs(&ifaddr) == -1) {
        if (ifaddr) {
            freeifaddrs(ifaddr);
        }
        mterror(WM_CONTROL_LOGTAG, "at getPrimaryIP(): getifaddrs() failed.");
        return agent_ip;
    }

    for (ifa = ifaddr; ifa; ifa = ifa->ifa_next){
        i++;
    }

    if(i == 0){
        mtdebug1(WM_CONTROL_LOGTAG, "No network interfaces found when reading agent IP.");
        return agent_ip;
    }

    os_calloc(i, sizeof(char *), ifaces_list);

    /* Create interfaces list */
    size = getIfaceslist(ifaces_list, ifaddr);

    if(!ifaces_list[0]){
        mtdebug1(WM_CONTROL_LOGTAG, "No network interfaces found when reading agent IP.");
        os_free(ifaces_list);
        freeifaddrs(ifaddr);
        return agent_ip;
    }

#ifdef __MACH__
    OSHash *gateways = OSHash_Create();
    OSHash_SetFreeDataPointer(gateways, (void (*)(void *)) freegate);
    if (getGatewayList(gateways) < 0){
        mtdebug1(WM_CONTROL_LOGTAG, "Unable to obtain the Default Gateway list");
        OSHash_Free(gateways);
        os_free(ifaces_list);
        freeifaddrs(ifaddr);
        return agent_ip;
    }
    gateway *gate;
#endif

    for (i=0; i<size; i++) {
        cJSON *object = cJSON_CreateObject();
#ifdef __linux__
        getNetworkIface_linux(object, ifaces_list[i], ifaddr);
#elif defined __MACH__
        if(gate = OSHash_Get(gateways, ifaces_list[i]), gate){
            if(!gate->isdefault){
                cJSON_Delete(object);
                continue;
            }
            if(gate->addr[0]=='l'){
                cJSON_Delete(object);
                continue;
            }
            getNetworkIface_bsd(object, ifaces_list[i], ifaddr, gate);
        }
#endif
        cJSON *interface = cJSON_GetObjectItem(object, "iface");
        cJSON *ipv4 = cJSON_GetObjectItem(interface, "IPv4");
        if(ipv4){
#ifdef __linux__
            cJSON * gateway = cJSON_GetObjectItem(ipv4, "gateway");
            if (gateway) {
                cJSON * metric = cJSON_GetObjectItem(ipv4, "metric");
                if (metric && metric->valueint < min_metric) {
                    cJSON *addresses = cJSON_GetObjectItem(ipv4, "address");
                    cJSON *address = cJSON_GetArrayItem(addresses,0);
                    if(agent_ip != NULL){
                        free(agent_ip);
                    }
                    os_strdup(address->valuestring, agent_ip);
                    min_metric = metric->valueint;
                }
            }
#elif defined __MACH__
            cJSON *addresses = cJSON_GetObjectItem(ipv4, "address");
            cJSON *address = cJSON_GetArrayItem(addresses,0);
            os_strdup(address->valuestring, agent_ip);
            cJSON_Delete(object);
            break;
#endif

        }
        cJSON_Delete(object);
    }
#if defined __MACH__
    OSHash_Free(gateways);
#endif

    freeifaddrs(ifaddr);
    for (i=0; ifaces_list[i]; i++){
        free(ifaces_list[i]);
    }

    free(ifaces_list);

#elif defined sun

    // Get number of interfaces

    int if_count = get_if_num();

    if (if_count == -1) {
        return NULL;
    }

    // Initialize configuration structure

    struct lifconf if_conf = { .lifc_family = AF_INET, .lifc_len = if_count * sizeof(struct lifreq) };
    if_conf.lifc_buf = malloc(if_conf.lifc_len);
    assert(if_conf.lifc_buf != NULL);

    // Create helper socket

    int fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (fd == -1) {
        goto end;
    }

    // Get interfaces

    if (ioctl(fd, SIOCGLIFCONF, &if_conf) == -1) {
        goto end;
    }

    // Scan interfaces

    int i;
    for (i = 0; i < if_count; i++) {
        struct lifreq * if_req = if_conf.lifc_req + i;

        // Get flags

        if (ioctl(fd, SIOCGLIFFLAGS, if_req) == -1) {
            goto end;
        }

        // Get the first interface that is up and is not loopback

        int flags = if_req->lifr_flags;

        if ((flags & IFF_UP) && (flags & IFF_LOOPBACK) == 0) {
            // Get IP address

            if (ioctl(fd, SIOCGLIFADDR, if_req) == -1) {
                goto end;
            }

            struct sockaddr_in * addr = (struct sockaddr_in *)&if_req->lifr_addr;
            agent_ip = strdup(inet_ntoa(addr->sin_addr));
            break;
        }
    }

end:
    if (fd != -1) {
        close(fd);
    }

    free(if_conf.lifc_buf);
#endif

    return agent_ip;
}

void *wm_control_main(){

    mtinfo(WM_CONTROL_LOGTAG, "Starting control thread.");

    send_ip();

    return NULL;
}

void wm_control_destroy(){}

wmodule *wm_control_read(){
    wmodule * module;

    os_calloc(1, sizeof(wmodule), module);
    module->context = &WM_CONTROL_CONTEXT;
    module->tag = strdup(module->context->name);

    return module;
}

cJSON *wm_control_dump() {
    cJSON *root = cJSON_CreateObject();
    cJSON *wm_wd = cJSON_CreateObject();
    cJSON_AddStringToObject(wm_wd,"enabled","yes");
    cJSON_AddItemToObject(root,"wazuh_control",wm_wd);
    return root;
}

void *send_ip(){
    int sock;
    int peer;
    char *buffer = NULL;
    char *response = NULL;
    ssize_t length;
    fd_set fdset;

    if (sock = OS_BindUnixDomain(DEFAULTDIR CONTROL_SOCK, SOCK_STREAM, OS_MAXSTR), sock < 0) {
        mterror(WM_CONTROL_LOGTAG, "Unable to bind to socket '%s': (%d) %s.", CONTROL_SOCK, errno, strerror(errno));
        return NULL;
    }

    while (1) {

        // Wait for socket
        FD_ZERO(&fdset);
        FD_SET(sock, &fdset);

        switch (select(sock + 1, &fdset, NULL, NULL, NULL)) {
        case -1:
            if (errno != EINTR) {
                mterror_exit(WM_CONTROL_LOGTAG, "At send_ip(): select(): %s", strerror(errno));
            }

            continue;

        case 0:
            continue;
        }

        if (peer = accept(sock, NULL, NULL), peer < 0) {
            if (errno != EINTR) {
                mterror(WM_CONTROL_LOGTAG, "At send_ip(): accept(): %s", strerror(errno));
            }

            continue;
        }

        os_calloc(IPSIZE + 1, sizeof(char), buffer);
        switch (length = OS_RecvUnix(peer, IPSIZE, buffer), length) {
        case -1:
            mterror(WM_CONTROL_LOGTAG, "At send_ip(): OS_RecvUnix(): %s", strerror(errno));
            break;

        case 0:
            mtinfo(WM_CONTROL_LOGTAG, "Empty message from local client.");
            close(peer);
            break;

        case OS_MAXLEN:
            mterror(WM_CONTROL_LOGTAG, "Received message > %i", MAX_DYN_STR);
            close(peer);
            break;

        default:
            response = getPrimaryIP();
            if(response){
                OS_SendUnix(peer, response, 0);
                free(response);
            }
            else{
                OS_SendUnix(peer,"Err",4);
            }
            close(peer);
        }
        free(buffer);
    }

    close(sock);
    return NULL;
}

#endif


<Canvas>
    <Kind>42</Kind>
    <Name>Presets</Name>
    <IsMinified>1</IsMinified>
    <XPosition>2.000000000</XPosition>
    <YPosition>416.000000000</YPosition>
</Canvas>
<Widget>
    <Kind>2</Kind>
    <Name>basic2</Name>
    <Value>0</Value>
</Widget>
<Widget>
    <Kind>2</Kind>
    <Name>BasicPreset</Name>
    <Value>0</Value>
</Widget>
<Widget>
    <Kind>2</Kind>
    <Name>j_simple</Name>
    <Value>1</Value>
</Widget>


/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.elasticsearch.painless;

/** Tests for xor operator across all types */
public class XorTests extends ScriptTestCase {

    public void testBasics() throws Exception {
        assertEquals(9 ^ 3, exec("return 9 ^ 3;"));
        assertEquals(9L ^ 3, exec("return 9L ^ 3;"));
        assertEquals(9 ^ 3L, exec("return 9 ^ 3L;"));
        assertEquals(10, exec("short x = 9; char y = 3; return x ^ y;"));
    }

    public void testInt() throws Exception {
        assertEquals(5 ^ 12, exec("int x = 5; int y = 12; return x ^ y;"));
        assertEquals(5 ^ -12, exec("int x = 5; int y = -12; return x ^ y;"));
        assertEquals(7 ^ 15 ^ 3, exec("int x = 7; int y = 15; int z = 3; return x ^ y ^ z;"));
    }

    public void testIntConst() throws Exception {
        assertEquals(5 ^ 12, exec("return 5 ^ 12;"));
        assertEquals(5 ^ -12, exec("return 5 ^ -12;"));
        assertEquals(7 ^ 15 ^ 3, exec("return 7 ^ 15 ^ 3;"));
    }

    public void testLong() throws Exception {
        assertEquals(5L ^ 12L, exec("long x = 5; long y = 12; return x ^ y;"));
        assertEquals(5L ^ -12L, exec("long x = 5; long y = -12; return x ^ y;"));
        assertEquals(7L ^ 15L ^ 3L, exec("long x = 7; long y = 15; long z = 3; return x ^ y ^ z;"));
    }

    public void testLongConst() throws Exception {
        assertEquals(5L ^ 12L, exec("return 5L ^ 12L;"));
        assertEquals(5L ^ -12L, exec("return 5L ^ -12L;"));
        assertEquals(7L ^ 15L ^ 3L, exec("return 7L ^ 15L ^ 3L;"));
    }

    public void testBool() throws Exception {
        assertEquals(false, exec("boolean x = true; boolean y = true; return x ^ y;"));
        assertEquals(true, exec("boolean x = true; boolean y = false; return x ^ y;"));
        assertEquals(true, exec("boolean x = false; boolean y = true; return x ^ y;"));
        assertEquals(false, exec("boolean x = false; boolean y = false; return x ^ y;"));
    }

    public void testBoolConst() throws Exception {
        assertEquals(false, exec("return true ^ true;"));
        assertEquals(true, exec("return true ^ false;"));
        assertEquals(true, exec("return false ^ true;"));
        assertEquals(false, exec("return false ^ false;"));
    }

    public void testIllegal() throws Exception {
        expectScriptThrows(ClassCastException.class, () -> {
            exec("float x = (float)4; int y = 1; return x ^ y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("double x = (double)4; int y = 1; return x ^ y");
        });
    }

    public void testDef() {
        expectScriptThrows(ClassCastException.class, () -> {
            exec("def x = (float)4; def y = (byte)1; return x ^ y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("def x = (double)4; def y = (byte)1; return x ^ y");
        });
        assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (byte)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (byte)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (short)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (short)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (char)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (char)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (int)1; return x ^ y"));

        assertEquals(5L, exec("def x = (byte)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (short)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (char)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (int)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));

        assertEquals(false, exec("def x = true;  def y = true; return x ^ y"));
        assertEquals(true,  exec("def x = true;  def y = false; return x ^ y"));
        assertEquals(true,  exec("def x = false; def y = true; return x ^ y"));
        assertEquals(false, exec("def x = false; def y = false; return x ^ y"));
    }

    public void testDefTypedLHS() {
        expectScriptThrows(ClassCastException.class, () -> {
            exec("float x = (float)4; def y = (byte)1; return x ^ y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("double x = (double)4; def y = (byte)1; return x ^ y");
        });
        assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (byte)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (byte)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (short)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (short)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (char)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (char)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (int)1; return x ^ y"));

        assertEquals(5L, exec("def x = (byte)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (short)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (char)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (int)4; def y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));

        assertEquals(false, exec("def x = true;  def y = true; return x ^ y"));
        assertEquals(true,  exec("def x = true;  def y = false; return x ^ y"));
        assertEquals(true,  exec("def x = false; def y = true; return x ^ y"));
        assertEquals(false, exec("def x = false; def y = false; return x ^ y"));
    }

    public void testDefTypedRHS() {
        expectScriptThrows(ClassCastException.class, () -> {
            exec("def x = (float)4; byte y = (byte)1; return x ^ y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("def x = (double)4; byte y = (byte)1; return x ^ y");
        });
        assertEquals(5, exec("def x = (byte)4; byte y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; byte y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; byte y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; byte y = (byte)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; byte y = (byte)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; short y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; short y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; short y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; short y = (short)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; short y = (short)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; char y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; char y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; char y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; char y = (char)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; char y = (char)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; int y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; int y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; int y = (int)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; int y = (int)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; int y = (int)1; return x ^ y"));

        assertEquals(5L, exec("def x = (byte)4; long y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (short)4; long y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (char)4; long y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (int)4; long y = (long)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; long y = (long)1; return x ^ y"));

        assertEquals(5, exec("def x = (byte)4; byte y = (byte)1; return x ^ y"));
        assertEquals(5, exec("def x = (short)4; short y = (short)1; return x ^ y"));
        assertEquals(5, exec("def x = (char)4; char y = (char)1; return x ^ y"));
        assertEquals(5, exec("def x = (int)4; int y = (int)1; return x ^ y"));
        assertEquals(5L, exec("def x = (long)4; long y = (long)1; return x ^ y"));

        assertEquals(false, exec("def x = true;  boolean y = true; return x ^ y"));
        assertEquals(true,  exec("def x = true;  boolean y = false; return x ^ y"));
        assertEquals(true,  exec("def x = false; boolean y = true; return x ^ y"));
        assertEquals(false, exec("def x = false; boolean y = false; return x ^ y"));
    }

    public void testCompoundAssignment() {
        // boolean
        assertEquals(false, exec("boolean x = true; x ^= true; return x;"));
        assertEquals(true, exec("boolean x = true; x ^= false; return x;"));
        assertEquals(true, exec("boolean x = false; x ^= true; return x;"));
        assertEquals(false, exec("boolean x = false; x ^= false; return x;"));
        assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] ^= true; return x[0];"));
        assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = true; x[0] ^= false; return x[0];"));
        assertEquals(true, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] ^= true; return x[0];"));
        assertEquals(false, exec("boolean[] x = new boolean[1]; x[0] = false; x[0] ^= false; return x[0];"));

        // byte
        assertEquals((byte) (13 ^ 14), exec("byte x = 13; x ^= 14; return x;"));
        // short
        assertEquals((short) (13 ^ 14), exec("short x = 13; x ^= 14; return x;"));
        // char
        assertEquals((char) (13 ^ 14), exec("char x = 13; x ^= 14; return x;"));
        // int
        assertEquals(13 ^ 14, exec("int x = 13; x ^= 14; return x;"));
        // long
        assertEquals((long) (13 ^ 14), exec("long x = 13L; x ^= 14; return x;"));
    }

    public void testBogusCompoundAssignment() {
        expectScriptThrows(ClassCastException.class, () -> {
            exec("float x = 4; int y = 1; x ^= y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("double x = 4; int y = 1; x ^= y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("int x = 4; float y = 1; x ^= y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("int x = 4; double y = 1; x ^= y");
        });
    }

    public void testCompoundAssignmentDef() {
        // boolean
        assertEquals(false, exec("def x = true; x ^= true; return x;"));
        assertEquals(true, exec("def x = true; x ^= false; return x;"));
        assertEquals(true, exec("def x = false; x ^= true; return x;"));
        assertEquals(false, exec("def x = false; x ^= false; return x;"));
        assertEquals(false, exec("def[] x = new def[1]; x[0] = true; x[0] ^= true; return x[0];"));
        assertEquals(true, exec("def[] x = new def[1]; x[0] = true; x[0] ^= false; return x[0];"));
        assertEquals(true, exec("def[] x = new def[1]; x[0] = false; x[0] ^= true; return x[0];"));
        assertEquals(false, exec("def[] x = new def[1]; x[0] = false; x[0] ^= false; return x[0];"));

        // byte
        assertEquals((byte) (13 ^ 14), exec("def x = (byte)13; x ^= 14; return x;"));
        // short
        assertEquals((short) (13 ^ 14), exec("def x = (short)13; x ^= 14; return x;"));
        // char
        assertEquals((char) (13 ^ 14), exec("def x = (char)13; x ^= 14; return x;"));
        // int
        assertEquals(13 ^ 14, exec("def x = 13; x ^= 14; return x;"));
        // long
        assertEquals((long) (13 ^ 14), exec("def x = 13L; x ^= 14; return x;"));
    }

    public void testDefBogusCompoundAssignment() {
        expectScriptThrows(ClassCastException.class, () -> {
            exec("def x = 4F; int y = 1; x ^= y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("def x = 4D; int y = 1; x ^= y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("int x = 4; def y = (float)1; x ^= y");
        });
        expectScriptThrows(ClassCastException.class, () -> {
            exec("int x = 4; def y = (double)1; x ^= y");
        });
    }
}