text:
// associated header
#include "Tasks/QPConstr.h"

// includes
// std
#include <cmath>

// RBDyn
#include <RBDyn/MultiBody.h>
#include <RBDyn/MultiBodyConfig.h>
#include <RBDyn/VisServo.h>

// sch
#include <sch/CD/CD_Pair.h>
#include <sch/S_Object/S_Object.h>

// Tasks
#include "Tasks/Bounds.h"
#include "utils.h"

namespace tasks
{

namespace qp
{

/**
 *															JointLimitsConstr
 */

JointLimitsConstr::JointLimitsConstr(const std::vector<rbd::MultiBody> & mbs, int robotIndex, QBound bound, double step)
: JointLimitsConstr(mbs, robotIndex, bound, {}, {}, step)
{
}

JointLimitsConstr::JointLimitsConstr(const std::vector<rbd::MultiBody> & mbs,
                                     int robotIndex,
                                     QBound bound,
                                     const AlphaDBound & aDBound,
                                     double step)
: JointLimitsConstr(mbs, robotIndex, bound, aDBound, {}, step)
{
}

JointLimitsConstr::JointLimitsConstr(const std::vector<rbd::MultiBody> & mbs,
                                     int robotIndex,
                                     QBound bound,
                                     const AlphaDBound & aDBound,
                                     const AlphaDDBound & aDDBound,
                                     double step)
: robotIndex_(robotIndex), alphaDBegin_(-1),
  alphaDOffset_(mbs[robotIndex].joint(0).dof() > 1 ? mbs[robotIndex].joint(0).dof() : 0), step_(step), qMin_(), qMax_(),
  qVec_(), alphaVec_(), lower_(), upper_(), alphaDLower_(), alphaDUpper_(), alphaDDLower_(), alphaDDUpper_(),
  prevAlphaD_()
{
  assert(std::size_t(robotIndex_) < mbs.size() && robotIndex_ >= 0);

  const rbd::MultiBody & mb = mbs[robotIndex_];

  // we don't manage joint with more than 1
  /// @todo remove this dirty hack
  int nrVars = mb.nrDof() - alphaDOffset_;
  qMin_.resize(nrVars);
  qMax_.resize(nrVars);
  qVec_.resize(mb.nrParams());
  alphaVec_.resize(mb.nrDof());
  alphaDLower_.resize(mb.nrDof());
  alphaDUpper_.resize(mb.nrDof());
  alphaDLower_.setConstant(-std::numeric_limits<double>::infinity());
  alphaDUpper_.setConstant(std::numeric_limits<double>::infinity());
  alphaDDLower_.resize(mb.nrDof());
  alphaDDUpper_.resize(mb.nrDof());
  alphaDDLower_.setConstant(-std::numeric_limits<double>::infinity());
  alphaDDUpper_.setConstant(std::numeric_limits<double>::infinity());
  prevAlphaD_.resize(mb.nrDof());
  prevAlphaD_.setZero();

  // if first joint is not managed remove it
  if(alphaDOffset_ != 0)
  {
    bound.lQBound[0] = {};
    bound.uQBound[0] = {};
  }

  rbd::paramToVector(bound.lQBound, qMin_);
  rbd::paramToVector(bound.uQBound, qMax_);

  lower_.setConstant(nrVars, -std::numeric_limits<double>::infinity());
  upper_.setConstant(nrVars, std::numeric_limits<double>::infinity());

  rbd::paramToVector(aDBound.lAlphaDBound, alphaDLower_);
  rbd::paramToVector(aDBound.uAlphaDBound, alphaDUpper_);

  rbd::paramToVector(aDDBound.lAlphaDDBound, alphaDDLower_);
  rbd::paramToVector(aDDBound.uAlphaDDBound, alphaDDUpper_);
  alphaDDLower_ *= step_;
  alphaDDUpper_ *= step_;
}

void JointLimitsConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mbs */, const SolverData & data)
{
  alphaDBegin_ = data.alphaDBegin(robotIndex_) + alphaDOffset_;
}

void JointLimitsConstr::update(const std::vector<rbd::MultiBody> & /* mbs */,
                               const std::vector<rbd::MultiBodyConfig> & mbcs,
                               const SolverData & /* data */)
{
  const rbd::MultiBodyConfig & mbc = mbcs[robotIndex_];

  double dts = step_ * step_ * 0.5;

  int vars = int(qMin_.rows());

  rbd::paramToVector(mbc.q, qVec_);
  rbd::paramToVector(mbc.alpha, alphaVec_);
  rbd::paramToVector(mbc.alphaD, prevAlphaD_);

  lower_.noalias() = qMin_ - qVec_.tail(vars) - alphaVec_.tail(vars) * step_;
  lower_ /= dts;

  upper_.noalias() = qMax_ - qVec_.tail(vars) - alphaVec_.tail(vars) * step_;
  upper_ /= dts;

  lower_ = lower_.cwiseMax(alphaDLower_).cwiseMax(alphaDDLower_ + prevAlphaD_);
  upper_ = upper_.cwiseMin(alphaDUpper_).cwiseMin(alphaDDUpper_ + prevAlphaD_);
}

std::string JointLimitsConstr::nameBound() const
{
  return "JointLimitsConstr";
}

std::string JointLimitsConstr::descBound(const std::vector<rbd::MultiBody> & mbs, int line)
{
  int jIndex = findJointFromVector(mbs[robotIndex_], line, false);
  return std::string("Joint: ") + mbs[robotIndex_].joint(jIndex).name();
}

int JointLimitsConstr::beginVar() const
{
  return alphaDBegin_;
}

const Eigen::VectorXd & JointLimitsConstr::Lower() const
{
  return lower_;
}

const Eigen::VectorXd & JointLimitsConstr::Upper() const
{
  return upper_;
}

/**
 *												DamperJointLimitsConstr
 */

DamperJointLimitsConstr::DamperJointLimitsConstr(const std::vector<rbd::MultiBody> & mbs,
                                                 int robotIndex,
                                                 const QBound & qBound,
                                                 const AlphaBound & aBound,
                                                 double interPercent,
                                                 double securityPercent,
                                                 double damperOffset,
                                                 double step)
: DamperJointLimitsConstr(mbs, robotIndex, qBound, aBound, {}, {}, interPercent, securityPercent, damperOffset, step)
{
}

DamperJointLimitsConstr::DamperJointLimitsConstr(const std::vector<rbd::MultiBody> & mbs,
                                                 int robotIndex,
                                                 const QBound & qBound,
                                                 const AlphaBound & aBound,
                                                 const AlphaDBound & aDBound,
                                                 double interPercent,
                                                 double securityPercent,
                                                 double damperOffset,
                                                 double step)
: DamperJointLimitsConstr(mbs,
                          robotIndex,
                          qBound,
                          aBound,
                          aDBound,
                          {},
                          interPercent,
                          securityPercent,
                          damperOffset,
                          step)
{
}

DamperJointLimitsConstr::DamperJointLimitsConstr(const std::vector<rbd::MultiBody> & mbs,
                                                 int robotIndex,
                                                 const QBound & qBound,
                                                 const AlphaBound & aBound,
                                                 const AlphaDBound & aDBound,
                                                 const AlphaDDBound & aDDBound,
                                                 double interPercent,
                                                 double securityPercent,
                                                 double damperOffset,
                                                 double step)
: robotIndex_(robotIndex), alphaDBegin_(-1), data_(), lower_(mbs[robotIndex].nrDof()), upper_(mbs[robotIndex].nrDof()),
  alphaDLower_(mbs[robotIndex].nrDof()), alphaDUpper_(mbs[robotIndex].nrDof()), alphaDDLower_(mbs[robotIndex].nrDof()),
  alphaDDUpper_(mbs[robotIndex].nrDof()), prevAlphaD_(mbs[robotIndex].nrDof()), step_(step), damperOff_(damperOffset)
{
  assert(std::size_t(robotIndex_) < mbs.size() && robotIndex_ >= 0);

  const rbd::MultiBody & mb = mbs[robotIndex_];

  for(int i = 0; i < mb.nrJoints(); ++i)
  {
    if(mb.joint(i).dof() == 1)
    {
      double dist = (qBound.uQBound[i][0] - qBound.lQBound[i][0]);
      data_.emplace_back(qBound.lQBound[i][0], qBound.uQBound[i][0], aBound.lAlphaBound[i][0], aBound.uAlphaBound[i][0],
                         dist * interPercent, dist * securityPercent, mb.jointPosInDof(i), i);
    }
  }

  rbd::paramToVector(aBound.lAlphaBound, lower_);
  rbd::paramToVector(aBound.uAlphaBound, upper_);
  alphaDLower_.setConstant(-std::numeric_limits<double>::infinity());
  alphaDUpper_.setConstant(std::numeric_limits<double>::infinity());
  alphaDDLower_.setConstant(-std::numeric_limits<double>::infinity());
  alphaDDUpper_.setConstant(std::numeric_limits<double>::infinity());
  rbd::paramToVector(aDBound.lAlphaDBound, alphaDLower_);
  rbd::paramToVector(aDBound.uAlphaDBound, alphaDUpper_);
  rbd::paramToVector(aDDBound.lAlphaDDBound, alphaDDLower_);
  rbd::paramToVector(aDDBound.uAlphaDDBound, alphaDDUpper_);
  alphaDDLower_ *= step_;
  alphaDDUpper_ *= step_;
  prevAlphaD_.setZero();
}

void DamperJointLimitsConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mbs */, const SolverData & data)
{
  alphaDBegin_ = data.alphaDBegin(robotIndex_);
}

void DamperJointLimitsConstr::update(const std::vector<rbd::MultiBody> & /* mbs */,
                                     const std::vector<rbd::MultiBodyConfig> & mbcs,
                                     const SolverData & /* data */)
{
  const rbd::MultiBodyConfig & mbc = mbcs[robotIndex_];
  rbd::paramToVector(mbc.alphaD, prevAlphaD_);

  for(DampData & d : data_)
  {
    double ld = mbc.q[d.jointIndex][0] - d.min;
    double ud = d.max - mbc.q[d.jointIndex][0];
    double alpha = mbc.alpha[d.jointIndex][0];

    lower_[d.alphaDBegin] = (d.minVel - alpha) / step_;
    upper_[d.alphaDBegin] = (d.maxVel - alpha) / step_;

    if(ld < d.iDist)
    {
      // damper(dist) < alpha
      // dist > 0 -> negative < alpha -> joint angle can decrease
      // dist < 0 -> positive < alpha -> joint angle must increase
      if(d.state != DampData::Low)
      {
        d.damping = std::abs(computeDamping(alpha, ld, d.iDist, d.sDist)) + damperOff_;
        d.state = DampData::Low;
      }

      double damper = -computeDamper(ld, d.iDist, d.sDist, d.damping);
      lower_[d.alphaDBegin] = std::max((damper - alpha) / step_, lower_[d.alphaDBegin]);
    }
    else if(ud < d.iDist)
    {
      // alpha < damper(dist)
      // dist > 0 -> alpha < positive -> joint angle can increase
      // dist < 0 -> alpha < negative -> joint angle must decrease
      if(d.state != DampData::Upp)
      {
        d.damping = std::abs(computeDamping(alpha, ud, d.iDist, d.sDist)) + damperOff_;
        d.state = DampData::Upp;
      }

      double damper = computeDamper(ud, d.iDist, d.sDist, d.damping);
      upper_[d.alphaDBegin] = std::min((damper - alpha) / step_, upper_[d.alphaDBegin]);
    }
    else
    {
      d.state = DampData::Free;
    }
  }
  lower_ = lower_.cwiseMax(alphaDLower_).cwiseMax(alphaDDLower_ + prevAlphaD_);
  upper_ = upper_.cwiseMin(alphaDUpper_).cwiseMin(alphaDDUpper_ + prevAlphaD_);
}

std::string DamperJointLimitsConstr::nameBound() const
{
  return "DamperJointLimitsConstr";
}

std::string DamperJointLimitsConstr::descBound(const std::vector<rbd::MultiBody> & mbs, int line)
{
  int jIndex = findJointFromVector(mbs[robotIndex_], line, false);
  return std::string("Joint: ") + mbs[robotIndex_].joint(jIndex).name();
}

int DamperJointLimitsConstr::beginVar() const
{
  return alphaDBegin_;
}

const Eigen::VectorXd & DamperJointLimitsConstr::Lower() const
{
  return lower_;
}

const Eigen::VectorXd & DamperJointLimitsConstr::Upper() const
{
  return upper_;
}

double DamperJointLimitsConstr::computeDamping(double alpha, double dist, double iDist, double sDist)
{
  return ((iDist - sDist) / (dist - sDist)) * alpha;
}

double DamperJointLimitsConstr::computeDamper(double dist, double iDist, double sDist, double damping)
{
  return damping * ((dist - sDist) / (iDist - sDist));
}

/**
 *													CollisionConstr
 */

sch::Matrix4x4 tosch(const sva::PTransformd & t)
{
  sch::Matrix4x4 m;
  const Eigen::Matrix3d & rot = t.rotation();
  const Eigen::Vector3d & tran = t.translation();

  for(int i = 0; i < 3; ++i)
  {
    for(int j = 0; j < 3; ++j)
    {
      m(i, j) = rot(j, i);
    }
  }

  m(0, 3) = tran(0);
  m(1, 3) = tran(1);
  m(2, 3) = tran(2);

  return m;
}

CollisionConstr::BodyCollData::BodyCollData(const rbd::MultiBody & mb,
                                            int rI,
                                            const std::string & bName,
                                            sch::S_Object * h,
                                            const sva::PTransformd & X,
                                            const Eigen::VectorXd & selector)
: hull(h), jac(mb, bName), X_op_o(X), rIndex(rI), bIndex(mb.bodyIndexByName(bName)), bodyName(bName), selector(selector)
{
}

CollisionConstr::CollData::CollData(std::vector<BodyCollData> bcds,
                                    int collId,
                                    sch::S_Object * body1,
                                    sch::S_Object * body2,
                                    double di,
                                    double ds,
                                    double damp,
                                    double dampOff)
: pair(new sch::CD_Pair(body1, body2)), normVecDist(Eigen::Vector3d::Zero()), di(di), ds(ds), damping(damp),
  bodies(std::move(bcds)), dampingType(damping > 0. ? DampingType::Hard : DampingType::Free), dampingOff(dampOff),
  collId(collId)
{
}

CollisionConstr::CollisionConstr(const std::vector<rbd::MultiBody> & mbs, double step)
: dataVec_(), step_(step), nrActivated_(0), totalAlphaD_(-1), AInEq_(), bInEq_(), fullJac_(), distJac_()
{
  int maxDof = std::max_element(mbs.begin(), mbs.end(), compareDof)->nrDof();
  fullJac_.resize(1, maxDof);
  distJac_.resize(1, maxDof);
}

void CollisionConstr::addCollision(const std::vector<rbd::MultiBody> & mbs,
                                   int collId,
                                   int r1Index,
                                   const std::string & r1BodyName,
                                   sch::S_Object * body1,
                                   const sva::PTransformd & X_op1_o1,
                                   int r2Index,
                                   const std::string & r2BodyName,
                                   sch::S_Object * body2,
                                   const sva::PTransformd & X_op2_o2,
                                   double di,
                                   double ds,
                                   double damping,
                                   double dampingOff,
                                   const Eigen::VectorXd & r1Selector,
                                   const Eigen::VectorXd & r2Selector)
{
  const rbd::MultiBody mb1 = mbs[static_cast<size_t>(r1Index)];
  const rbd::MultiBody mb2 = mbs[static_cast<size_t>(r2Index)];
  std::vector<BodyCollData> bodies;
  if(mb1.nrDof() > 0)
  {
    assert(r1Selector.size() == 0 || r1Selector.size() == mb1.nrDof());
    bodies.emplace_back(mb1, r1Index, r1BodyName, body1, X_op1_o1, r1Selector);
  }
  if(mb2.nrDof() > 0)
  {
    assert(r2Selector.size() == 0 || r2Selector.size() == mb2.nrDof());
    bodies.emplace_back(mb2, r2Index, r2BodyName, body2, X_op2_o2, r1Index == r2Index ? r1Selector : r2Selector);
  }
  dataVec_.emplace_back(std::move(bodies), collId, body1, body2, di, ds, damping, dampingOff);
}

bool CollisionConstr::rmCollision(int collId)
{
  auto it =
      std::find_if(dataVec_.begin(), dataVec_.end(), [collId](const CollData & data) { return data.collId == collId; });
  if(it != dataVec_.end())
  {
    dataVec_.erase(it);
    return true;
  }

  return false;
}

auto CollisionConstr::getCollisionData(int collId) const -> const CollData &
{
  auto it =
      std::find_if(dataVec_.begin(), dataVec_.end(), [&](const CollData & data) { return data.collId == collId; });
  if(it != dataVec_.end())
  {
    return *it;
  }
  throw std::runtime_error("No collision with the requested id");
}

std::size_t CollisionConstr::nrCollisions() const
{
  return dataVec_.size();
}

void CollisionConstr::reset()
{
  dataVec_.clear();
}

void CollisionConstr::updateNrCollisions()
{
  AInEq_.setZero(static_cast<Eigen::DenseIndex>(dataVec_.size()), nrVars_);
  bInEq_.setZero(static_cast<Eigen::DenseIndex>(dataVec_.size()));
}

void CollisionConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mb */, const SolverData & data)
{
  totalAlphaD_ = data.totalAlphaD();
  nrVars_ = data.nrVars();
  updateNrCollisions();
}

void CollisionConstr::update(const std::vector<rbd::MultiBody> & mbs,
                             const std::vector<rbd::MultiBodyConfig> & mbcs,
                             const SolverData & data)
{
  using namespace Eigen;

  sch::Point3 pb1Tmp;
  sch::Point3 pb2Tmp;

  nrActivated_ = 0;
  for(CollData & d : dataVec_)
  {
    // update moving hull position
    for(BodyCollData & bcd : d.bodies)
    {
      const rbd::MultiBodyConfig & mbc = mbcs[static_cast<size_t>(bcd.rIndex)];
      bcd.hull->setTransformation(tosch(bcd.X_op_o * mbc.bodyPosW[static_cast<size_t>(bcd.bIndex)]));
    }

    d.distance = d.pair->getClosestPoints(pb1Tmp, pb2Tmp);
    d.distance = d.distance >= 0 ? std::sqrt(d.distance) : -std::sqrt(-d.distance);

    d.p1 << pb1Tmp[0], pb1Tmp[1], pb1Tmp[2];
    d.p2 << pb2Tmp[0], pb2Tmp[1], pb2Tmp[2];

    Eigen::Vector3d normVecDist = (d.p1 - d.p2) / (d.distance != 0 ? d.distance : sch::epsilon);

    // compute nearestPoint in body coordinate
    Eigen::Vector3d nearestPoint = d.p1;
    for(std::size_t i = 0; i < d.bodies.size(); ++i)
    {
      BodyCollData & bcd = d.bodies[i];
      const rbd::MultiBodyConfig & mbc = mbcs[static_cast<size_t>(bcd.rIndex)];
      nearestPoint =
          (sva::PTransformd(nearestPoint) * mbc.bodyPosW[static_cast<size_t>(bcd.bIndex)].inv()).translation();

      // change the jacobian end point
      bcd.jac.point(nearestPoint);
      nearestPoint = d.p2;
    }

    if(d.distance < d.di)
    {
      // automatic damping computation if needed
      if(d.dampingType == CollData::DampingType::Free)
      {
        d.dampingType = CollData::DampingType::Soft;
        d.damping = computeDamping(mbs, mbcs, d, normVecDist, d.distance);
      }

      double dampers = d.damping * ((d.distance - d.ds) / (d.di - d.ds));

      Vector3d nf = normVecDist;
      Vector3d onf = d.normVecDist;
      Vector3d dnf = (nf - onf) / step_;

      double sign = 1.;
      bInEq_(nrActivated_) = dampers;
      AInEq_.block(nrActivated_, 0, 1, totalAlphaD_).setZero();
      for(std::size_t i = 0; i < d.bodies.size(); ++i)
      {
        BodyCollData & bcd = d.bodies[i];
        const rbd::MultiBody & mb = mbs[static_cast<size_t>(bcd.rIndex)];
        const rbd::MultiBodyConfig & mbc = mbcs[static_cast<size_t>(bcd.rIndex)];

        // Compute body1
        const MatrixXd & jac = bcd.jac.jacobian(mb, mbc);
        Eigen::Vector3d pSpeed = bcd.jac.velocity(mb, mbc).linear();
        Eigen::Vector3d pNormalAcc = bcd.jac.normalAcceleration(mb, mbc, data.normalAccB(bcd.rIndex)).linear();

        distJac_.block(0, 0, 1, bcd.jac.dof()).noalias() =
            (nf * step_ * sign).transpose() * jac.block(3, 0, 3, bcd.jac.dof());

        bcd.jac.fullJacobian(mb, distJac_.block(0, 0, 1, bcd.jac.dof()), fullJac_);

        double jqdn = pSpeed.dot(nf);
        double jqdnd = pSpeed.dot(dnf * step_);
        double jdqdn = pNormalAcc.dot(nf * step_);

        if(bcd.selector.size() == 0)
        {
          AInEq_.block(nrActivated_, data.alphaDBegin(bcd.rIndex), 1, mb.nrDof()).noalias() -=
              fullJac_.block(0, 0, 1, mb.nrDof());
        }
        else
        {
          AInEq_.block(nrActivated_, data.alphaDBegin(bcd.rIndex), 1, mb.nrDof()).noalias() -=
              fullJac_.block(0, 0, 1, mb.nrDof()) * bcd.selector.asDiagonal();
        }
        bInEq_(nrActivated_) += sign * (jqdn + jqdnd + jdqdn);
        // little hack
        // the max iteration number is two, so at the second iteration
        // sign will be -1
        sign = -1.;
      }
      ++nrActivated_;
    }
    else
    {
      if(d.dampingType == CollData::DampingType::Soft)
      {
        d.dampingType = CollData::DampingType::Free;
      }
    }

    d.normVecDist = normVecDist;
  }
}

std::string CollisionConstr::nameInEq() const
{
  return "SelfCollisionConstr";
}

std::string CollisionConstr::descInEq(const std::vector<rbd::MultiBody> & mbs, int line)
{
  int curLine = 0;
  for(CollData & d : dataVec_)
  {
    double dist = d.pair->getDistance();
    dist = dist >= 0 ? std::sqrt(dist) : -std::sqrt(-dist);
    if(dist < d.di)
    {
      if(curLine == line)
      {
        std::stringstream ss;
        for(const BodyCollData & bcd : d.bodies)
        {
          const rbd::MultiBody & mb = mbs[static_cast<size_t>(bcd.rIndex)];
          ss << "robot: " << bcd.rIndex << std::endl;
          ss << "body: " << mb.body(bcd.bIndex).name() << std::endl;
        }
        ss << "collId: " << d.collId << std::endl;
        ss << "dist: " << dist << std::endl;
        ss << "di: " << d.di << std::endl;
        ss << "ds: " << d.ds << std::endl;
        ss << "damp: " << d.damping + d.dampingOff << std::endl;
        return ss.str();
      }
      ++curLine;
    }
  }
  return "";
}

int CollisionConstr::nrInEq() const
{
  return nrActivated_;
}

int CollisionConstr::maxInEq() const
{
  return int(dataVec_.size());
}

const Eigen::MatrixXd & CollisionConstr::AInEq() const
{
  return AInEq_;
}

const Eigen::VectorXd & CollisionConstr::bInEq() const
{
  return bInEq_;
}

double CollisionConstr::computeDamping(const std::vector<rbd::MultiBody> & mbs,
                                       const std::vector<rbd::MultiBodyConfig> & mbcs,
                                       const CollData & cd,
                                       const Eigen::Vector3d & normVecDist,
                                       double dist) const
{
  Eigen::Vector3d diffVel(Eigen::Vector3d::Zero());
  double sign = 1.;
  for(std::size_t i = 0; i < cd.bodies.size(); ++i)
  {
    const BodyCollData & bcd = cd.bodies[i];
    const rbd::MultiBody & mb = mbs[static_cast<size_t>(bcd.rIndex)];
    const rbd::MultiBodyConfig & mbc = mbcs[static_cast<size_t>(bcd.rIndex)];

    Eigen::Vector3d velW = bcd.jac.velocity(mb, mbc).linear();

    diffVel += sign * velW;
    // little hack
    // the max iteration number is two, so at the second iteration
    // sign will be -1
    sign = -1;
  }

  double distDot = std::abs((diffVel).dot(normVecDist));

  /// @todo find a bette solution.
  // use a value slightly upper ds if dist <= ds
  double fixedDist = dist <= cd.ds ? cd.ds + (cd.di - cd.ds) * 0.2 : dist;
  return ((cd.di - cd.ds) / (fixedDist - cd.ds)) * distDot + cd.dampingOff;
}

/**
 *													CoMIncPlaneConstr
 */

CoMIncPlaneConstr::PlaneData::PlaneData(int planeId,
                                        const Eigen::Vector3d & normal,
                                        double offset,
                                        double di,
                                        double ds,
                                        double damping,
                                        double dampOff,
                                        const Eigen::Vector3d & speed,
                                        const Eigen::Vector3d & normalDot)
: normal(normal), normalDot(normalDot), offset(offset), dist(0.), di(di), ds(ds), damping(damping), planeId(planeId),
  dampingType(damping > 0. ? DampingType::Hard : DampingType::Free), dampingOff(dampOff), speed(speed)
{
}

CoMIncPlaneConstr::CoMIncPlaneConstr(const std::vector<rbd::MultiBody> & mbs, int robotIndex, double step)
: robotIndex_(robotIndex), alphaDBegin_(-1), dataVec_(), step_(step), nrVars_(0), nrActivated_(0), activated_(0),
  jacCoM_(mbs[robotIndex]), AInEq_(), bInEq_()
{
}

void CoMIncPlaneConstr::addPlane(int planeId,
                                 const Eigen::Vector3d & normal,
                                 double offset,
                                 double di,
                                 double ds,
                                 double damping,
                                 double dampingOff)
{
  dataVec_.emplace_back(planeId, normal, offset, di, ds, damping, dampingOff, Eigen::Vector3d::Zero(),
                        Eigen::Vector3d::Zero());
  activated_.reserve(dataVec_.size());
}

void CoMIncPlaneConstr::addPlane(int planeId,
                                 const Eigen::Vector3d & normal,
                                 double offset,
                                 double di,
                                 double ds,
                                 double damping,
                                 const Eigen::Vector3d & speed,
                                 const Eigen::Vector3d & normalDot,
                                 double dampingOff)
{
  dataVec_.emplace_back(planeId, normal, offset, di, ds, damping, dampingOff, speed, normalDot);
  activated_.reserve(dataVec_.size());
}

bool CoMIncPlaneConstr::rmPlane(int planeId)
{
  auto it = std::find_if(dataVec_.begin(), dataVec_.end(),
                         [planeId](const PlaneData & data) { return data.planeId == planeId; });

  if(it != dataVec_.end())
  {
    dataVec_.erase(it);
    return true;
  }
  // no need to resize activated, only the max size is important

  return false;
}

std::size_t CoMIncPlaneConstr::nrPlanes() const
{
  return dataVec_.size();
}

void CoMIncPlaneConstr::reset()
{
  dataVec_.clear();
}

void CoMIncPlaneConstr::updateNrPlanes()
{
  AInEq_.setZero(dataVec_.size(), nrVars_);
  bInEq_.setZero(dataVec_.size());
}

void CoMIncPlaneConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mbs */, const SolverData & data)
{
  alphaDBegin_ = data.alphaDBegin(robotIndex_);
  nrVars_ = data.nrVars();
  updateNrPlanes();
}

void CoMIncPlaneConstr::update(const std::vector<rbd::MultiBody> & mbs,
                               const std::vector<rbd::MultiBodyConfig> & mbcs,
                               const SolverData & data)
{
  using namespace Eigen;

  const rbd::MultiBody & mb = mbs[robotIndex_];
  const rbd::MultiBodyConfig & mbc = mbcs[robotIndex_];

  Eigen::Vector3d com = rbd::computeCoM(mb, mbc);

  for(std::size_t i = 0; i < dataVec_.size(); ++i)
  {
    PlaneData & d = dataVec_[i];
    d.dist = d.normal.dot(com) + d.offset;
    if(d.dist <= d.di)
    {
      // don't allocate since we set capacity to dataVec_ size
      activated_.push_back(i);
    }
    else
    {
      if(d.dampingType == PlaneData::DampingType::Soft)
      {
        d.dampingType = PlaneData::DampingType::Free;
      }
    }
  }

  nrActivated_ = 0;
  if(!activated_.empty())
  {
    const MatrixXd & jacComMat = jacCoM_.jacobian(mb, mbc);
    Eigen::Vector3d comSpeed = jacCoM_.velocity(mb, mbc);
    Eigen::Vector3d comNormalAcc = jacCoM_.normalAcceleration(mb, mbc, data.normalAccB(robotIndex_));

    for(std::size_t i : activated_)
    {
      PlaneData & d = dataVec_[i];
      double distDot = d.normal.dot(comSpeed - d.speed);
      double distDDot = d.normalDot.dot(comSpeed - d.speed);

      if(d.dampingType == PlaneData::DampingType::Free)
      {
        d.dampingType = PlaneData::DampingType::Soft;

        /// @todo find a bette solution.
        // use a value slightly upper ds if dist <= ds
        double fixedDist = d.dist <= d.ds ? d.ds + (d.di - d.ds) * 0.2 : d.dist;
        d.damping = -((d.di - d.ds) / (fixedDist - d.ds)) * distDot + d.dampingOff;
      }

      double dampers = d.damping * ((d.dist - d.ds) / (d.di - d.ds));

      // -dt*normal^T*J_com
      AInEq_.block(nrActivated_, alphaDBegin_, 1, mb.nrDof()).noalias() = -(step_ * d.normal.transpose()) * jacComMat;

      // dampers + ddot + dt*normal^T*J*qdot
      bInEq_(nrActivated_) = dampers + distDot + step_ * (d.normal.dot(comNormalAcc) + distDDot);
      ++nrActivated_;
    }
  }

  activated_.clear(); // don't free the vector, just say there is 0 elements
}

std::string CoMIncPlaneConstr::nameInEq() const
{
  return "CoMIncPlaneConstr";
}

std::string CoMIncPlaneConstr::descInEq(const std::vector<rbd::MultiBody> & /* mbs */, int line)
{
  int curLine = 0;
  for(PlaneData & d : dataVec_)
  {
    if(d.dist < d.di)
    {
      if(curLine == line)
      {
        std::stringstream ss;
        ss << "planeId: " << d.planeId << std::endl;
        ss << "normal: " << d.normal.transpose();
        ss << "offset: " << d.offset << std::endl;
        ss << "dist: " << d.dist << std::endl;
        ss << "di: " << d.di << std::endl;
        ss << "ds: " << d.ds << std::endl;
        ss << "damp: " << d.damping << std::endl;
        ss << "speed: " << d.speed.transpose() << std::endl;
        ss << "normalDot: " << d.normalDot.transpose() << std::endl;
        return ss.str();
      }
      ++curLine;
    }
  }
  return "";
}

int CoMIncPlaneConstr::nrInEq() const
{
  return nrActivated_;
}

int CoMIncPlaneConstr::maxInEq() const
{
  return int(dataVec_.size());
}

const Eigen::MatrixXd & CoMIncPlaneConstr::AInEq() const
{
  return AInEq_;
}

const Eigen::VectorXd & CoMIncPlaneConstr::bInEq() const
{
  return bInEq_;
}

/**
 *													GripperTorqueConstr
 */

GripperTorqueConstr::GripperData::GripperData(const ContactId & cId,
                                              double tl,
                                              const Eigen::Vector3d & o,
                                              const Eigen::Vector3d & a)
: contactId(cId), torqueLimit(tl), origin(o), axis(a)
{
}

GripperTorqueConstr::GripperTorqueConstr() : dataVec_(), AInEq_(), bInEq_() {}

void GripperTorqueConstr::addGripper(const ContactId & cId,
                                     double torqueLimit,
                                     const Eigen::Vector3d & origin,
                                     const Eigen::Vector3d & axis)
{
  dataVec_.emplace_back(cId, torqueLimit, origin, axis);
}

bool GripperTorqueConstr::rmGripper(const ContactId & contactId)
{
  auto it = std::find_if(dataVec_.begin(), dataVec_.end(),
                         [contactId](const GripperData & data) { return data.contactId == contactId; });

  if(it != dataVec_.end())
  {
    dataVec_.erase(it);
    return true;
  }

  return false;
}

void GripperTorqueConstr::reset()
{
  dataVec_.clear();
}

void GripperTorqueConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mbs */, const SolverData & data)
{
  using namespace Eigen;
  AInEq_.setZero(dataVec_.size(), data.nrVars());
  bInEq_.setZero(dataVec_.size());

  int line = 0;
  int nrUni = int(data.unilateralContacts().size());
  for(const GripperData & gd : dataVec_)
  {
    for(std::size_t bi = 0; bi < data.bilateralContacts().size(); ++bi)
    {
      const BilateralContact & bc = data.bilateralContacts()[bi];

      if(bc.contactId == gd.contactId)
      {
        int col = data.lambdaBegin(int(bi) + nrUni);
        // Torque applied on the gripper motor
        // Sum_i^nrF  T_i·( p_i^T_o x f_i)
        for(std::size_t i = 0; i < bc.r1Cones.size(); ++i)
        {
          Vector3d T_o_p = bc.r1Points[i] - gd.origin;
          for(std::size_t j = 0; j < bc.r1Cones[i].generators.size(); ++j)
          {
            // we use abs because the contact force cannot apply
            // negative torque on the gripper
            AInEq_(line, col) = std::abs(gd.axis.transpose() * (T_o_p.cross(bc.r1Cones[i].generators[j])));
            ++col;
          }
        }
        bInEq_(line) = gd.torqueLimit;
        ++line;
        break;
      }
      // if the bodyId is not found the AInEq_ and BInEq_ line stay at zero
    }
  }
}

void GripperTorqueConstr::update(const std::vector<rbd::MultiBody> & /* mbs */,
                                 const std::vector<rbd::MultiBodyConfig> & /* mbcs */,
                                 const SolverData & /* data */)
{
}

std::string GripperTorqueConstr::nameInEq() const
{
  return "GripperTorqueConstr";
}

std::string GripperTorqueConstr::descInEq(const std::vector<rbd::MultiBody> & /* mbs */, int line)
{
  std::stringstream ss;
  const GripperData & gd = dataVec_[line];

  ss << gd.contactId.r1BodyName << "/" << gd.contactId.r2BodyName << std::endl;
  ss << "limits: " << gd.torqueLimit << std::endl;
  return ss.str();
}

int GripperTorqueConstr::maxInEq() const
{
  return static_cast<int>(dataVec_.size());
}

const Eigen::MatrixXd & GripperTorqueConstr::AInEq() const
{
  return AInEq_;
}

const Eigen::VectorXd & GripperTorqueConstr::bInEq() const
{
  return bInEq_;
}

/**
 *															BoundedSpeedConstr
 */

BoundedSpeedConstr::BoundedSpeedConstr(const std::vector<rbd::MultiBody> & mbs, int robotIndex, double timeStep)
: robotIndex_(robotIndex), cont_(), fullJac_(6, mbs[robotIndex_].nrDof()), A_(), lower_(), upper_(), nrVars_(0),
  timeStep_(timeStep)
{
}

void BoundedSpeedConstr::addBoundedSpeed(const std::vector<rbd::MultiBody> & mbs,
                                         const std::string & bodyName,
                                         const Eigen::Vector3d & bodyPoint,
                                         const Eigen::MatrixXd & dof,
                                         const Eigen::VectorXd & speed)
{
  addBoundedSpeed(mbs, bodyName, bodyPoint, dof, speed, speed);
}

void BoundedSpeedConstr::addBoundedSpeed(const std::vector<rbd::MultiBody> & mbs,
                                         const std::string & bodyName,
                                         const Eigen::Vector3d & bodyPoint,
                                         const Eigen::MatrixXd & dof,
                                         const Eigen::VectorXd & lowerSpeed,
                                         const Eigen::VectorXd & upperSpeed)
{
  rbd::Jacobian jac(mbs[robotIndex_], bodyName, bodyPoint);
  cont_.push_back({jac, dof, lowerSpeed, upperSpeed, bodyName});
}

bool BoundedSpeedConstr::removeBoundedSpeed(const std::string & bodyName)
{
  auto it = std::find_if(cont_.begin(), cont_.end(),
                         [bodyName](const BoundedSpeedData & data) { return data.bodyName == bodyName; });

  if(it != cont_.end())
  {
    cont_.erase(it);
    return true;
  }

  return false;
}

void BoundedSpeedConstr::resetBoundedSpeeds()
{
  cont_.clear();
}

std::size_t BoundedSpeedConstr::nrBoundedSpeeds() const
{
  return cont_.size();
}

void BoundedSpeedConstr::updateBoundedSpeeds()
{
  updateNrEq();
}

void BoundedSpeedConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mbs */, const SolverData & data)
{
  alphaDBegin_ = data.alphaDBegin(robotIndex_);
  nrVars_ = data.nrVars();
  updateNrEq();
}

void BoundedSpeedConstr::update(const std::vector<rbd::MultiBody> & mbs,
                                const std::vector<rbd::MultiBodyConfig> & mbcs,
                                const SolverData & data)
{
  using namespace Eigen;

  const rbd::MultiBody & mb = mbs[robotIndex_];
  const rbd::MultiBodyConfig & mbc = mbcs[robotIndex_];

  // TargetSpeed = V_k + A_{k+1}*dt
  // TargetSpeed - V_k = J_k*alphaD_{k+1} + JD_k*alpha_k
  // (TargetSpeed - V_k)/dt - JD_k*alpha_k = J_k*alphaD_{k+1}

  int index = 0;
  for(std::size_t i = 0; i < cont_.size(); ++i)
  {
    int rows = int(cont_[i].dof.rows());

    // AEq
    const MatrixXd & jac = cont_[i].jac.bodyJacobian(mb, mbc);
    cont_[i].jac.fullJacobian(mb, jac, fullJac_);
    A_.block(index, alphaDBegin_, rows, mb.nrDof()).noalias() = cont_[i].dof * fullJac_;

    // BEq
    Vector6d speed = cont_[i].jac.bodyVelocity(mb, mbc).vector();
    Vector6d normalAcc = cont_[i].jac.bodyNormalAcceleration(mb, mbc, data.normalAccB(robotIndex_)).vector();

    lower_.segment(index, rows).noalias() = cont_[i].dof * (-normalAcc - (speed / timeStep_));
    upper_.segment(index, rows).noalias() = lower_.segment(index, rows);

    lower_.segment(index, rows).noalias() += (cont_[i].lSpeed / timeStep_);
    upper_.segment(index, rows).noalias() += (cont_[i].uSpeed / timeStep_);
    index += rows;
  }
}

std::string BoundedSpeedConstr::nameGenInEq() const
{
  return "BoundedSpeedConstr";
}

std::string BoundedSpeedConstr::descGenInEq(const std::vector<rbd::MultiBody> & mbs, int line)
{
  int curRow = 0;
  for(const BoundedSpeedData & c : cont_)
  {
    curRow += int(c.dof.rows());
    if(line < curRow)
    {
      return std::string("Body: ") + mbs[robotIndex_].body(c.body).name();
    }
  }
  return std::string("");
}

int BoundedSpeedConstr::maxGenInEq() const
{
  return int(A_.rows());
}

const Eigen::MatrixXd & BoundedSpeedConstr::AGenInEq() const
{
  return A_;
}

const Eigen::VectorXd & BoundedSpeedConstr::LowerGenInEq() const
{
  return lower_;
}

const Eigen::VectorXd & BoundedSpeedConstr::UpperGenInEq() const
{
  return upper_;
}

void BoundedSpeedConstr::updateNrEq()
{
  int nrEq = 0;
  for(const BoundedSpeedData & c : cont_)
  {
    nrEq += int(c.dof.rows());
  }

  A_.setZero(nrEq, nrVars_);
  lower_.setZero(nrEq);
  upper_.setZero(nrEq);
}

/**
 *													ImageConstr
 */

ImageConstr::PointData::PointData(const Eigen::Vector2d & pt, const double d) : point2d(pt), depthEstimate(d) {}

ImageConstr::RobotPointData::RobotPointData(const std::string & bn, const sva::PTransformd & X, const rbd::Jacobian & j)
: bName(bn), X_b_p(X), jac(j)
{
}

ImageConstr::ImageConstr(const std::vector<rbd::MultiBody> & mbs,
                         int robotIndex,
                         const std::string & bName,
                         const sva::PTransformd & X_b_gaze,
                         double step,
                         double constrDirection)
: dataVec_(), dataVecRob_(), robotIndex_(robotIndex), bodyIndex_(mbs[robotIndex].bodyIndexByName(bName)),
  alphaDBegin_(-1), nrVars_(0), step_(step), accelFactor_(0.5 * step * step), nrActivated_(0),
  jac_(mbs[robotIndex], bName), X_b_gaze_(X_b_gaze),
  L_img_(new Eigen::Matrix<double, 2, 6>(Eigen::Matrix<double, 2, 6>::Zero())),
  surfaceVelocity_(new Eigen::Matrix<double, 6, 1>(Eigen::Matrix<double, 6, 1>::Zero())),
  L_Z_dot_(new Eigen::Matrix<double, 1, 6>(Eigen::Matrix<double, 1, 6>::Zero())),
  L_img_dot_(new Eigen::Matrix<double, 2, 6>(Eigen::Matrix<double, 2, 6>::Zero())),
  speed_(new Eigen::Vector2d(Eigen::Vector2d::Zero())), normalAcc_(new Eigen::Vector2d(Eigen::Vector2d::Zero())),
  jacMat_(2, mbs[robotIndex].nrDof()), iDistMin_(new Eigen::Vector2d(Eigen::Vector2d::Zero())),
  iDistMax_(new Eigen::Vector2d(Eigen::Vector2d::Zero())), sDistMin_(new Eigen::Vector2d(Eigen::Vector2d::Zero())),
  sDistMax_(new Eigen::Vector2d(Eigen::Vector2d::Zero())), damping_(0.), dampingOffset_(0.), ineqInversion_(1),
  constrDirection_(constrDirection), AInEq_(), bInEq_()
{
}

ImageConstr::ImageConstr(const ImageConstr & rhs)
: dataVec_(rhs.dataVec_), dataVecRob_(rhs.dataVecRob_), robotIndex_(rhs.robotIndex_), bodyIndex_(rhs.bodyIndex_),
  alphaDBegin_(rhs.alphaDBegin_), nrVars_(rhs.nrVars_), step_(rhs.step_), accelFactor_(rhs.accelFactor_),
  nrActivated_(rhs.nrActivated_), jac_(rhs.jac_), X_b_gaze_(rhs.X_b_gaze_),
  L_img_(new Eigen::Matrix<double, 2, 6>(*rhs.L_img_)),
  surfaceVelocity_(new Eigen::Matrix<double, 6, 1>(*rhs.surfaceVelocity_)),
  L_Z_dot_(new Eigen::Matrix<double, 1, 6>(*rhs.L_Z_dot_)),
  L_img_dot_(new Eigen::Matrix<double, 2, 6>(*rhs.L_img_dot_)), speed_(new Eigen::Vector2d(*rhs.speed_)),
  normalAcc_(new Eigen::Vector2d(*rhs.normalAcc_)), jacMat_(rhs.jacMat_),
  iDistMin_(new Eigen::Vector2d(*rhs.iDistMin_)), iDistMax_(new Eigen::Vector2d(*rhs.iDistMax_)),
  sDistMin_(new Eigen::Vector2d(*rhs.sDistMin_)), sDistMax_(new Eigen::Vector2d(*rhs.sDistMax_)),
  damping_(rhs.damping_), dampingOffset_(rhs.dampingOffset_), ineqInversion_(rhs.ineqInversion_),
  constrDirection_(rhs.constrDirection_), AInEq_(rhs.AInEq_), bInEq_(rhs.bInEq_)
{
}

ImageConstr & ImageConstr::operator=(const ImageConstr & rhs)
{
  if(&rhs != this)
  {
    dataVec_ = rhs.dataVec_;
    dataVecRob_ = rhs.dataVecRob_;
    robotIndex_ = rhs.robotIndex_;
    bodyIndex_ = rhs.bodyIndex_;
    alphaDBegin_ = rhs.alphaDBegin_;
    nrVars_ = rhs.nrVars_;
    step_ = rhs.step_;
    accelFactor_ = rhs.accelFactor_;
    nrActivated_ = rhs.nrActivated_;
    jac_ = rhs.jac_;
    X_b_gaze_ = rhs.X_b_gaze_;
    *L_img_ = *rhs.L_img_;
    *surfaceVelocity_ = *rhs.surfaceVelocity_;
    *L_Z_dot_ = *rhs.L_Z_dot_;
    *L_img_dot_ = *rhs.L_img_dot_;
    *speed_ = *rhs.speed_;
    *normalAcc_ = *rhs.normalAcc_;
    jacMat_ = rhs.jacMat_;
    *iDistMin_ = *rhs.iDistMin_;
    *iDistMax_ = *rhs.iDistMax_;
    *sDistMin_ = *rhs.sDistMin_;
    *sDistMax_ = *rhs.sDistMax_;
    damping_ = rhs.damping_;
    dampingOffset_ = rhs.dampingOffset_;
    ineqInversion_ = rhs.ineqInversion_;
    constrDirection_ = rhs.constrDirection_;
    AInEq_ = rhs.AInEq_;
    bInEq_ = rhs.bInEq_;
  }
  return *this;
}

int ImageConstr::addPoint(const Eigen::Vector2d & point2d, const double depthEstimate)
{
  dataVec_.emplace_back(point2d, depthEstimate);
  return int(dataVec_.size()) - 1;
}

int ImageConstr::addPoint(const Eigen::Vector3d & point3d)
{
  Eigen::Vector2d point2d(point3d[0] / point3d[2], point3d[1] / point3d[2]);
  int id = addPoint(point2d, point3d[2]);
  return id;
}

void ImageConstr::addPoint(const std::vector<rbd::MultiBody> & mbs,
                           const std::string & bName,
                           const sva::PTransformd & X_b_p)
{
  dataVecRob_.emplace_back(bName, X_b_p, rbd::Jacobian(mbs[robotIndex_], bName));
}

void ImageConstr::reset()
{
  dataVec_.clear();
  dataVecRob_.clear();
}

void ImageConstr::updatePoint(const int pointId, const Eigen::Vector2d & point2d)
{
  dataVec_[pointId].point2d = point2d;
}

void ImageConstr::updatePoint(const int pointId, const Eigen::Vector2d & point2d, const double depthEstimate)
{
  dataVec_[pointId] = PointData(point2d, depthEstimate);
}

void ImageConstr::updatePoint(const int pointId, const Eigen::Vector3d & point3d)
{
  Eigen::Vector2d point2d_(point3d[0] / point3d[2], point3d[1] / point3d[2]);
  dataVec_[pointId] = PointData(point2d_, point3d[2]);
}

void ImageConstr::setLimits(const Eigen::Vector2d & min,
                            const Eigen::Vector2d & max,
                            const double iPercent,
                            const double sPercent,
                            const double damping,
                            const double dampingOffsetPercent)
{
  // precompute avoidance boundaries
  Eigen::Vector2d dist = max - min;
  *iDistMin_ = min + constrDirection_ * iPercent * dist;
  *iDistMax_ = max - constrDirection_ * iPercent * dist;
  *sDistMin_ = min + constrDirection_ * sPercent * dist;
  *sDistMax_ = max - constrDirection_ * sPercent * dist;

  damping_ = damping;
  dampingOffset_ = constrDirection_ * dampingOffsetPercent * damping;
}

void ImageConstr::computeComponents(const rbd::MultiBody & mb,
                                    const rbd::MultiBodyConfig & mbc,
                                    const SolverData & data,
                                    const Eigen::Vector2d & point2d,
                                    const double depth,
                                    rbd::Jacobian & jac,
                                    const int bodyIndex,
                                    const sva::PTransformd & X_b_p,
                                    Eigen::MatrixXd & fullJacobian,
                                    Eigen::Vector2d & bCommonTerm)
{
  // compute speed term
  rbd::imagePointJacobian(point2d, depth, *L_img_);
  *surfaceVelocity_ = (jac.velocity(mb, mbc, X_b_p)).vector();
  *speed_ = (*L_img_) * (*surfaceVelocity_);

  // compute norm accel term
  rbd::depthDotJacobian(*speed_, depth, *L_Z_dot_);
  rbd::imagePointJacobianDot(point2d, *speed_, depth, (*L_Z_dot_) * (*surfaceVelocity_), *L_img_dot_);
  *normalAcc_ = (*L_img_)
                    * (jac.normalAcceleration(mb, mbc, data.normalAccB(robotIndex_), X_b_p,
                                              sva::MotionVecd(Eigen::Vector6d::Zero())))
                          .vector()
                + (*L_img_dot_) * (*surfaceVelocity_);

  // compute the shortened jacobian
  const auto & shortJacMat =
      accelFactor_ * (*L_img_) * jac.jacobian(mb, mbc, X_b_p * mbc.bodyPosW[bodyIndex]).block(0, 0, 6, jac.dof());

  // fill objects to return for the QP
  jac.fullJacobian(mb, shortJacMat, fullJacobian);
  bCommonTerm = -step_ * (*speed_) - accelFactor_ * (*normalAcc_);
}

void ImageConstr::updateNrVars(const std::vector<rbd::MultiBody> & /* mbs */, const SolverData & data)
{
  alphaDBegin_ = data.alphaDBegin(robotIndex_);
  nrVars_ = data.nrVars();
  int nrRows = int(2 * (dataVec_.size() + dataVecRob_.size()));
  AInEq_.setZero(nrRows, nrVars_);
  bInEq_.setZero(nrRows);
}

void ImageConstr::update(const std::vector<rbd::MultiBody> & mbs,
                         const std::vector<rbd::MultiBodyConfig> & mbcs,
                         const SolverData & data)
{
  nrActivated_ = 0;

  const rbd::MultiBodyConfig & mbc = mbcs[robotIndex_];
  const rbd::MultiBody & mb = mbs[robotIndex_];

  // For each independent point
  for(const PointData & ptdata : dataVec_)
  {
    Eigen::Vector2d point2d_ = ptdata.point2d;

    Eigen::Vector2d bCommonTerm;
    computeComponents(mb, mbc, data, ptdata.point2d, ptdata.depthEstimate, jac_, bodyIndex_, X_b_gaze_, jacMat_,
                      bCommonTerm);

    // For x and y
    for(std::size_t i = 0; i < 2; ++i)
    {
      bool isConstrActive = false;
      std::size_t iOther = (i == 0) ? 1 : 0;

      // check occlusion constraint if it is within the 2D image bounds
      if((constrDirection_ == 1.)
         || ((point2d_[iOther] > (*iDistMin_)[iOther]) && (point2d_[iOther] < (*iDistMax_)[iOther])))
      {
        if((constrDirection_ * point2d_[i] < constrDirection_ * (*iDistMin_)[i]) // check min
           && ((constrDirection_ == 1.) || (point2d_[i] < 0.))) // handle occlusion constraint ambiquity
        {
          if(constrDirection_ * point2d_[i] > constrDirection_ * (*sDistMin_)[i])
          {
            isConstrActive = true;
            ineqInversion_ = -1. * constrDirection_;
            bInEq_(nrActivated_) =
                constrDirection_
                    * (damping_ * ((point2d_[i] - (*sDistMin_)[i]) / ((*iDistMin_)[i] - (*sDistMin_)[i]))
                       - dampingOffset_)
                + ineqInversion_ * bCommonTerm[i];
          }
          else
          {
            // give maxmimum avoidance when in the safety limit
            bInEq_(nrActivated_) = -constrDirection_ * dampingOffset_ + ineqInversion_ * bCommonTerm[i];
          }
        }
        else if((constrDirection_ * point2d_[i] > constrDirection_ * (*iDistMax_)[i]) // check max
                && ((constrDirection_ == 1.) || (point2d_[i] > 0.))) // handle occlusion constraint ambiquity
        {
          if(constrDirection_ * point2d_[i] < constrDirection_ * (*sDistMax_)[i])
          {
            isConstrActive = true;
            ineqInversion_ = 1. * constrDirection_;
            bInEq_(nrActivated_) =
                constrDirection_
                    * (damping_ * ((point2d_[i] - (*sDistMax_)[i]) / ((*iDistMax_)[i] - (*sDistMax_)[i]))
                       - dampingOffset_)
                + ineqInversion_ * bCommonTerm[i];
          }
          else
          {
            // give maxmimum avoidance when in the safety limit
            bInEq_(nrActivated_) = -constrDirection_ * dampingOffset_ + ineqInversion_ * bCommonTerm[i];
          }
        }
      }

      // fill the needed QP constraint data
      if(isConstrActive)
      {
        // update the QP inequality constraint variables
        AInEq_.block(nrActivated_, alphaDBegin_, 1, mb.nrDof()) = ineqInversion_ * jacMat_.block(i, 0, 1, mb.nrDof());
        ++nrActivated_;
      }
    }
  }
}

std::string ImageConstr::nameInEq() const
{
  return "ImageConstr";
}

std::string ImageConstr::descInEq(const std::vector<rbd::MultiBody> & /* mbs */, int line)
{
  int curLine = 0;
  for(std::size_t i = 0; i < dataVec_.size(); ++i)
  {
    // For x and y
    for(std::size_t j = 0; j < 2; ++j)
    {
      if(curLine == line)
      {
        std::stringstream ss;
        ss << "pointId: " << i << std::endl;
        if(j == 0)
        {
          ss << "x" << std::endl;
        }
        else
        {
          ss << "y" << std::endl;
        }
        ss << "normalized 2d location: " << std::endl << dataVec_[i].point2d << std::endl;
        return ss.str();
      }
      ++curLine;
    }
  }
  return "";
}

int ImageConstr::nrInEq() const
{
  return nrActivated_;
}

int ImageConstr::maxInEq() const
{
  return int(2 * (dataVec_.size() + dataVecRob_.size()));
}

const Eigen::MatrixXd & ImageConstr::AInEq() const
{
  return AInEq_;
}

const Eigen::VectorXd & ImageConstr::bInEq() const
{
  return bInEq_;
}

} // namespace qp

} // namespace tasks


text:
Newsletter Contact Us
red-logo
Police begin to question the story of missing boy's mother | UPDATE
Though police maintain that the mother of missing 2-year-old Sky Metalwala has cooperated with the investigation, holes are beginning to appear in her story.
By Nat Levy • November 7, 2011 5:01 pm
A sign calling for public help in finding Redmond 2-year-old Sky Metalwala shines bright on 112th Ave. N.E. in Bellevue
Police said Wednesday they were able to determine that Julia Biryukova's silver Acura Integra – which she said ran out of gas Sunday morning – had enough fuel to drive for a considerable amount of time. Combined with her unwillingness to take a lie-detector test, Biryukova has become a source of police frustration.
"The story doesn't add up, the whereabouts of Sky are unknown, and Mom's story is falling apart day to day; and her lack of cooperation so far in providing more information proactively and submitting to a polygraph doesn't help," said Bellevue police Maj. Mike Johnson.
City crews are continuing to test the car's mechanics Thursday to determine if anything is wrong with the vehicle.
Johnson said police will discuss the possibility of considering Biryukova a person of interest in the case, but she has answered all police questions through her attorney, and has not been named a suspect.
The focus of the investigation continues to be getting information from those closest to Sky and Biryukova, who lives in Redmond, so they can piece together the days and weeks that lead up to the boy being reported as missing Sunday.
"The people that were close to Sky and Julia are the people that know what happened to Sky," Johnson told reporters Wednesday morning. "If everyone cooperates, we should have answers we need."
The boy's father, Solomon Metalwala will take a second lie-detector test after the first one proved to be too emotionally trying.
Solomon and Biryukova were going through a divorce and a custody battle before the boy disappeared.
A second individual, whom Johnson called a "close friend" has come in for polygraph test, police said.
Experts have interviewed Sky's 4-year-old sister, a talk Johnson called "frustrating." He said they received very few answers to their questions, but the daughter did confirm that Sky was in the car that morning wrapped in a blanket.
Police noted that Biryukova had numerous pictures of the 4-year-old girl on her Facebook page and in the home, but no pictures of the boy.
Sky was reported missing Sunday morning when he was allegedly left in the car, with at least one door unlocked, while Biryukova and her 4-year-old daughter walked to a nearby gas station. Biryukova told police she was taking Sky to Overlake Hospital Medical Center because he was dealing with an undisclosed illness.
Other than polygraph tests, Johnson said resources from the FBI, Bellevue, Redmond and King County will focus on DNA tests from samples found in Biryukova's Acura Integra and her Redmond apartment.
Johnson said police will conduct DNA tests of interview subjects and the boy's family to see if they are left with any suspect samples.
Police and FBI agents searched Biryukova's downtown Redmond apartment and questioned neighbors and only one neighbor reported seeing the boy within the last two weeks. But Johnson said this wasn't an unusual circumstance because the family is known to be reclusive.
Johnson said he was "incredulous" of Biryukova's decision and movements on the morning when she left Sky in the unlocked car near the 2400 block of 112th Avenue Northeast.
"Many of us are parents as well as police officers, and when you hear this story that mom has told, you have to scratch your head and wonder why," Johnson said. "If that's what really what happened, why? This kid was sick; she was on the way to the hospital with him. Beyond that, why would you leave a 2-year-old alone in the car?"
If Sky was indeed in the vehicle that day, it wouldn't be the first time he was left alone in a car.
Solomon and Biryukova were previously charged with reckless endangerment and leaving a child unattended in a sports utility vehicle in 2009 in a Target parking lot in Redmond when Sky was three months old, according to court documents. Police had to ask that the vehicle's owners be paged in order to get the parents to come out to the vehicle, the documents said.
The charges were dismissed in February of this year after the parents took court-ordered parenting classes and completed community service, the documents stated.
Police along with resources from King County combed the nearby land looking for the boy, but the search came up empty, and it was suspended Sunday night.
The boy's father Solomon lives in Kirkland with his younger brother, Sam, who said he believes someone kidnapped his nephew.
"Somebody has the child," he said. "We just don't know who it is."
The boy's disappearance comes at the height of a custody fight between Biryukova and Solomon, who is puzzled by Biryukova's account of the details leading up to his son's disappearance.
"I don't understand why she would leave a little baby in the car," Solomon told reporters at his Bellevue attorney's office Monday afternoon. "The whole story is puzzling."
Sam said Biryukova has not allowed Solomon to see either of his children since last November.
Biryukova claimed in court documents that Solomon had an anger problem and was abusive, while Solomon said in other court documents that Biryukova was battling a mental illness and was a threat to her children.
Sam confirmed that the couple agreed to a tentative compromise just last week that would allow Solomon to have some visitation with Sky and his older sister.
Solomon filed for divorce in June 2010 and that same month Biryukova requested a protection order and in it she said her husband had been physically abusive toward her and had threatened to kill her if she sought custody of their children.
Last December, a social worker determined there was "preponderance of evidence" that Solomon had struck his daughter.
Meanwhile, Solomon alleged Biryukova was battling a mental illness, was suicidal and had dreams of harming her children, according to a divorce court document filed in King County Superior Court."We're trying to think very positive," said Sam, Solomon's brother.
"We just hope that he's safe and someone will bring him back."
U.S. Postal Service back to looking for new Redmond downtown location
Redmond girls place third at 4A state cross country meet
Redmond-based PaidPunch app encourages repeat...
By Nat Levy
Police make public request to...
No firm date set for...
Former Bellevue City Council member...
© 2023 Redmond Reporter and Sound Publishing. All Rights Reserved.

redpajama_set_name: RedPajamaCommonCrawl


text:
package org.apache.samza.runtime;

import java.io.Serializable;
import org.apache.samza.annotation.InterfaceStability;
import org.apache.samza.config.Config;

/**
 * This interface class defines the factory method to create an instance of {@link ProcessorLifecycleListener}.
 */
@InterfaceStability.Evolving
public interface ProcessorLifecycleListenerFactory extends Serializable {
  /**
   * Create an instance of {@link ProcessorLifecycleListener} for the StreamProcessor
   *
   * @param pContext the context of the corresponding StreamProcessor. Note that {@link ProcessorContext} is just a
   *                 placeholder before we have a proper implementation of general context in SAMZA-1714
   * @param config the configuration of the corresponding StreamProcessor
   * @return the {@link ProcessorLifecycleListener} callback object for the StreamProcessor
   */
  ProcessorLifecycleListener createInstance(ProcessorContext pContext, Config config);
}

redpajama_set_name: RedPajamaGithub


text:
Weird Circle - The Goblet
#70. NBC syndication. "The Goblet". A bride-to-be falls in love with a strange silversmith. Toasting with wine takes on a more serious tone in this story as one man remembers his tragic past. Franchesca is of low birth yet Donaldo the governor of the island fell madly in love and showered her with gifts in her favored silver. Ferdinand the silversmith is a master craftsman who's work, it seems, embodies a strange lifelike quality...for this becomes the strange whimsy of beautiful Franchesca. The bitter recollections of his Excellency, Donaldo Ronaldi become more and more explicit until we learn of the true nature of this awful wine goblet and what fate lay before the unfortunate Franchesca.
The Weird Circle was a syndicated series produced in New York and licensed by Mutual, and later, NBC's Red network. For two seasons, it cranked out 39 shows (78 total) consisting mostly of radio adaptations of classic horror stories
The show's strength was stories from famous writers of the two genres, including Robert Lewis Stevenson, Victor Hugo, Edgar Alan Poe and even Charles Dickens. Most all of the stories came from the Victorian era or older.
Shop for Classic Horror Shows


Show manager Liz Holmes has added two classes to the Clemson Fall Classic schedule. Class #1A will be ASB 3-Gaited Park - Amateur/Jr. Exhibitor. Class #76A will be ASB 3-Gaited Show Pleasure Stake - Jr. Exhibitor. The Clemson Fall Classic is set to be held November 12-13 at the T. Ed Garrison Arena in Clemson, SC.


Pam Rhodes is best known as the familiar face of the BBC's Songs of Praise, and here she brings together her personal selection of carols, poems, Bible readings and other inspirational passages from a wide range of sources.
As well as the usual old favourites - from Hark the Herald Angels Sing to the stories of the shepherds and the wise men visiting the baby Jesus - there are plenty of lighter moments, with excerpts from Gervase Phinn's memoirs and funny poems by modern writers. Alongside the items themselves Pam shares some of her own Christmas reminiscences and explores the resonance of the Christmas story for all our lives in her trademark inviting and heartwarming style.
The middle of November is normally far to early to be thinking about Christmas, but it's clearly already on many people's minds especially with Black Friday coming up and the countdown of shopping days has already begun. So it is probably the right time to have a look at this book from Songs Of Praise presenter Pam Rhodes. Here she presents this book "Tidings Of Comfort And Joy" which was initially published in 2015, but with limited exposure has been reprinted this year in plenty of time for the festive season.
This book has a wide possibilities for audiences, although I think it will probably suit older readers the best, having said that, I quite enjoyed the blend of anecdotes, thoughts and ideas and of course explanations of bits of the Christmas story. Within Christian circles there are people who feel that we are moving away from the origins of the celebration and Pam does a great job of balancing that line of thinking with embracing the more commercial elements of the festive season. She lays out the familiar ideas of Father Christmas with Saint Nicolas, Black Peter and the evolution into the Santa Claus that we know today. She does this in an entertaining fashion interspersing information with readings, poems and other quotes and writings.
She goes through various elements of the Christmas story, from the announcement of the birth of Jesus, along with some ideas of when Jesus' birth actually took place including information about how people have identified the most likely date and time of year, and how this matches with why we celebrate Christmas in December. She doesn't forget that Jesus grew up and had a mission when he was older, but the real focus is on how the story can influence our thinking.
There are some funny and thought-provoking Christmas related anecdotes in this book, and I am sure that many ministers looking for inspiration for their advent services would find this book useful. I had heard many of them before, but there were a couple that required relaying to other members of my family because they tickled my sense of humour.
This is a book that is written with a gentle touch. It has a soft subtle sense of fun, humour and, most of all, warmth running through it. It contains a lot of Pam's personality on every page. I loved the stories about Pam's home life at Christmas, particularly the bit about her husband getting very possessive of the Christmas lights. Of course these days it's all LEDs and they are not quite the same as the old fairy lights around the house or on the tree.
I think the older generation will love this book to remind them of tradition, years gone by and of course the Birth of Christ, the very reason that so many people celebrate December 25th.


text:
New Texts Out Now: Najat Rahman, In the Wake of the Poetic: Palestinian Artists after Darwish
Najat Rahman, In the Wake of the Poetic: Palestinian Artists after Darwish. Syracuse: Syracuse University Press, 2015.
Jadaliyya (J): What made you write this book?
Najat Rahman (NR): This book was conceived as a tribute to Mahmoud Darwish after his passing away. I found the most appropriate way for me to pay homage to the poet was to write about Palestinian artists in his wake who have proliferated on the international scene in the last two decades. Initially, I thought I would focus exclusively on a new generation of Palestinian poets, a work I had begun in 2000. There are so many compelling voices that merit substantial and sustained attention, some of whom I evoke in my work, like Abdul Raheem Shaikh and Mahmoud Abu Hashhash. These are poets who have forged their unique voices as they contended with a strong poetic tradition (Darwish, Qasim, Zayyad) while remaining connected to that tradition. As I was not expecting a wide-ranging dialogue between artists and the poetry of Mahmoud Darwish, although such a phenomenon is finally not so surprising, I widened the scope of the project to include not only poets but performance and visual artists, filmmakers, and musicians. I also included a French-German artist, Till Roeskens, who collaborated with the Palestinians of Aida Camp. In fact, the engagement with Darwish's legacy by artists is not confined solely to Palestinian or Arab ones. I recently learned of a traveling art exhibit by an art collective in Colorado around the work of Darwish. It is one of many.
One art installation crystallized this project for me. I came across a young artist's installation in al-Bireh in the winter of 2009, where the artist was carrying on a dialogue with Darwish. Although I had been observing visual artists evoking Darwish and engaging with his work, it had not occurred to me to deliberately consider visual, cinematic, and performance art as visual counterparts to his poetry, as well as the writing of other Palestinian authors, to explore this dialogue and intersection between his poetry and their art. The stunning recognition of Palestinian artists for their innovative work, work that is often intermedial, multilingual, and diasporic, also propelled me to consider this exciting development.
I was also conscious of a passing away of a number of intellectuals and writers of Darwish's generation who struggled through intellectual and creative work for a free voice, for home, for the ability to be and to create. The passing away of Emil Habiby, Jabra Ibrahim Jabra, Tawfiq Zayyad, Fadwa Tuqan, Ibrahim Abu-Lughod, Edward Said, and later Samih al-Qasim happened almost within a span of a decade. The voices of Said and Abu-Lughod were particularly critical for those of us in the diaspora. They were fine examples of thinkers that intervened in the present. Said seemed to recognize in his reading of Mona Hatoum and Emily Jacir how art may be increasingly the displaced space not only for true politics but also for free thought.
J: What particular topics, issues, and literatures does the book address?
NR: Ilan Pappé has argued that the 1990s have heralded a new period of creativity in the wake of the Oslo Accords, "as a result of the decentralization of the Palestinian political scene." I wanted to explore through the different artistic media the aesthetics and politics of Palestinian art "post-Oslo" in poetry, film, and performative and visual art, as well as highlight its significant presence on the international scene. Following particularly from Jacques Rancière, Judith Butler, and Giorgio Agamben, I was interested in examining a series of questions. If, according to Rancière, very little, if any, politics exists today, is art the displaced place for it? Is Palestinian art reconfiguring art as true politics? How does Palestinian art negotiate this relation between aesthetics and politics, without collapsing them into one another or negating their relation? How does the diasporic inform the national? How are we to understand these diverse articulations of belonging in diasporic contexts and "without the conditions of belonging"?
I argue that Palestinian art, local and diasporic, articulates an aesthetic founded on loss, dispersion, dispossession, and transformation. It interrupts dominant regimes, constituting acts of dissension and intervention, reinscribing belonging, orienting it toward solidarity and future. In this context, I look at the work of artists and writers such as Suheir Hammad, Ghassan Zaqtan, Elia Suleiman, Mona Hatoum, Sharif Waked, Eman Haram, and others. For instance, Suheir Hammad's Breaking Poems (2008), which pays tribute to the poetry of Mahmoud Darwish, engages Darwish in many instances through interpretation of some of his verses, interrupting monolingual readings, reinscribing belonging in a diasporic space of poetry and of solidarity, as she evokes other dispossessed peoples. As she marks a passage between her poetry and that of Darwish, her poetic language is one that inhabits and is inhabited by both languages, English and Arabic, an English constituted by Arabic. She evokes such poems in Limatha Tarakta al-Hisana Wahidan (Why Did You Leave the Horse Alone?) as "A Rhythm for Mu'allaqat…," when the poetic voice proclaims:
I am my language
This language of mine pendants from stars encircling the
embraces of the beloved: migrated
They took the place and migrated
they took the words and the fallen heart migrated with them
This is rendered in the verses of Hammad, in the poem "Break (Me)" as:
ana my language always broken all
ways lost ana my language wa
i miss my people
Hammad continues a poetry interrupted with the death of Darwish in 2008, the same year as the publication of her book Breaking Poems. It presents poetic creation as a significant act of interpretation and subject reformation.
J: Who do you hope will read this book, and what sort of impact would you like it to have?
NR: I hope this book will fortify even more the interest in the many exciting artists and writers in Palestine and in the diaspora. These are artists who, despite their many divergences, have created an aesthetic and poetic space of transformation where belonging, memory, loss, dispossession are inscribed. I also hope that their engagement (and that of other artists) with Darwish's work reminds us why poetry matters, why Darwish`s voice is a living voice. In an expanding occupation, language has become a casualty to violence, distortion, and disconnection. Poetry, on the other hand, teaches measure, meaning, truth, beauty, feeling, relation.
This is also a personal book, one that inscribes my voice, as I read and consider an aesthetic phenomenon. Having faced the challenges of relating a story of loss and dispossession that is ongoing, a story that need not negate others, I felt I needed another language to tell it. It is an effort at such a language, a common language. It is nonetheless connected to my work on Assia Djebar. Djebar's innovative use of narrative form and cinematic language were very much grounded in a reading of history and in a quest for aesthetic and political freedom. Darwish and Djebar both expressed a "longing of a century," were readers of a present, while also looking toward a future.
J: What other projects are you working on now?
NR: I just completed another project, with Gayatri Devi, Humor in Middle Eastern Cinema. This is an edited volume published by Wayne State University Press this past December. It explores the emancipatory possibilities of humor, especially in contexts of collective loss and state violence.
As I began my academic career with my work on Mahmoud Darwish and Assia Djebar, I would like to return to Djebar, who also passed away this year. Like Edward Said, Djebar wrote compellingly on the fundamental relation between interpretation and freedom. In all her work, but especially in Loin de Médine: Filles d'Ismaël (Far from Medina) and L'Amour, la fantasia (Fantasia: An Algerian Cavalcade), Djebar patiently reflects on the political stakes of interpretation, on the work of interpretation as a necessary path to individual and collective freedom. In "Nationalism, Human Rights, and Interpretation," Said wrote: "There is hardly an instance when the connection between freedom and interpretation is as urgent, as literally concrete, as it is for the Palestinian people…a large part of whose existence and fate has been interpreted away in the West in order to deny us the same freedom and interpretation granted Israeli Jews…The time has finally come to join and recognize these two peoples together as indeed their common actuality in historic Palestine already has joined them together. Only then can interpretation be for, rather than only about, freedom."
Excerpts from In the Wake of the Poetic: Palestinian Artists after Darwish
Jacques Rancière reminds us that politics is "the cluster of perceptions and practices that shape this common world…a way of framing, among sensory data, a specific sphere of experience…a partition of the sensible, of the visible and the sayable." Politics emerges also as a particular speech act performed when those excluded or subordinated speak out in "a struggle to have one's voice heard and oneself recognized."
Mona Hatoum, The Negotiating Table (1983), enacts a politics of remembering and belonging. A powerful, macabre, and visceral image reveals a corpse shrouded and lying on the surface of a wooden table: murdered, possibly tortured, and yet it breathes—a living death. Absent political figures are missing on the opposing empty chairs; the installation announces art as preoccupied with death in its violent forms and with the death of politics. Hatoum, speaking about The Negotiating Table, explains: "I was lying on a table, my body covered with entrails, bandages, and blood and wrapped up in a body bag. There were chairs around the table and sound tapes of speeches of Western leaders talking about peace. It was basically a juxtaposition of two elements, one referring to the physical reality and brutality of the situation and the other to the way it is represented and dealt with in the West."
What is common life becomes this mutilated body; what is on the table and what cannot be easily ignored is precisely this violence, and yet it is not addressed by the rhetoric of official political speeches that pretend to be the only viable discourses. Rancière highlights how dissensual speech is transformed into private noise and excluded from the political space, a predicament of being "loud and muted," in the words of Suheir Hammad. Rancière writes: "If there is someone you do not wish to recognize as a political being, you begin by…not understanding what he says, by not hearing what issues from his mouth as discourse."
The Negotiating Table evokes a primary language that announces there is violence, there is death, there is loss in the present, which has to be acknowledged and addressed...and which the art will not allow to be covered over with official discourses. Hammad expresses in her poems the predicament of those asked to adopt a language in contradiction to their lived lives: "We no longer know language," she writes in Breaking Poems. She suggests that the very discourse about Palestine is occupied: "humiliate a people distract the rest / … / …new world old words / this ain't living / words are against us /there is a math only subtracts" (19). Hammad demands a new language, a "break into language insurgent" (39). The poetic or artistic experience becomes an antidote to a discourse that has served as a math of dispossession. She writes: "language can't math me / i experience exponentially" (23). This art of experience (as well as of expression) counters this "math a myth wa language a lie" (35). Dispossession as a math of subtraction was…perpetuated by consensual political discourses that separate and classify into hierarchies of identity and power. This art by Hammad, Hatoum, Haram, the refugees of Camp Aida, Hany Abu Assad, Elia Suleiman, Sharif Waked, Emily Jacir, and others is one that names the violence, pierces through the din of discourses.
Hatoum made this performance in the wake of the Sabra and Shatila massacres of September 1982 perpetrated by the Lebanese Christian Phalange forces under Israel's watch. Hatoum calls this horrific event "the most shattering experience of my life." One could also fast forward and consider this image in relation to the period after Beirut, especially after the Oslo Accords (and after Gaza), where such speeches continued and were amplified at the same rate as that of increased aggressive settlements and violence.
Hatoum, who was born in Beirut and lives in London, combines the visuals of the absent political partners in the wake of dreadful violence and the sound of empty speeches about peace and negotiation. Hatoum's art makes a claim on the present and is in this sense a thing of the future. The Negotiating Table becomes emblematic of this recent Palestinian art, a commencement and a commandment, "a new way of framing a specific experience."
[Excerpted from Najat Rahman, In the Wake of the Poetic: Palestinian Artists after Darwish, by permission of the author. © 2015 Syracuse University Press. For more information, or to purchase this book, click here.]
Wednesday, October 07, 2015 - 9:00:00 AM


This stoneware mug is so named because of the surviving pieces excavated from an 18th century pottery located in Yorktown. Our large mug is 6" tall and 4" wide. It holds between 26 - 28 oz. This is a new and updated version of the Yorktown mug. All mugs are thrown individually and will vary somewhat.


text:
Understanding Society
Mind the Gender Gap: From rhetoric to reality
June 11, 2019Understanding Society: It's a Woman's World
In 2018, we celebrated 100 years of women's suffrage in the UK. While the centenary milestone was celebrated, the media has been dominated by stories of gender inequality both in and outside of the workplace. Artificial barriers are preventing women from progressing in their work lives, and we know from Ipsos research that equal pay is a key concern for women in the UK. The government has recently taken steps to address this through requiring reporting on equal pay, and social movements such as #pressforprogress may be having an effect too. But is this enough to smash the glass ceiling?
In this year's annual Captains of Industry survey, Ipsos spoke to 100 of the top business leaders in the UK about their views on diversity in the boardroom.
Women and diversity in the boardroom
Considering the focus in the media, the increase in Captains saying that they actively promote and champion diversity and inclusion in their companies seems unsurprising. Over nine in ten Captains now say that they agree with this statement, with 65% stating that they strongly agree, up from 44% in 2016. Three in four Captains (77%) agree that they are actively trying to increase the number of women on their main board, reflecting commitment to gender diversity and the heightened profile of gender equality. The number that strongly agree has also nearly doubled since 2016.
However, the number that are actively trying to increase the representation of ethnic minorities is far lower, with just half of Captains agreeing. What is most remarkable about this finding is that this means the nine in ten Captains who say they are actively promoting and championing diversity and inclusion in their companies may only be doing this because of the heightened rhetoric around women and gender equality, potentially as a result of #MeToo movements and initiatives such as the gender pay gap reporting.
The 9 in 10 Captains of Industry who say they are actively promoting and championing diversity and inclusion in their companies may only be doing this because of the heightened rhetoric around women and gender equality
Equal pay and the gender pay gap reporting
As our research for International Women's Day shows, equal pay is the most important issue facing women in Britain, with 29% of people citing it as an issue4 . But nearly half (48%) of Captains say that they have not taken any action as a result of the reporting requirement aside from reporting it. While rhetoric may be improving, there is less evidence of real change at the top.
Of the 9,961 companies that filed by the deadline of 4th April, the hourly median gender pay gap reported is 9.6% – no significant improvement from 9.7% last year5 . Additionally, over four in ten private companies that have published their latest gender pay gap are reporting wider gaps than they did last year. One challenge facing employers is the fact that some measures designed to lower the gender pay gap in the long term could increase the gap in the short term – such as hiring more young women. According to the CBI, 24% report they are placing a greater focus on improving gender diversity in entry-level recruitment.
Are we making progress?
To take stock, last year, research shows that there were more people called Dave leading FTSE 100 companies than there were women or people from ethnic minority group. There were nine called Dave, five from a minority ethnic background and six female chief executives of FTSE 100 companies. Of these six women, five were appointed in the last five years.
Optimistic perceptions of reality and potential for progress have a complicated relationship. We need to think that things have got better to believe that we can further improve them. But we cannot let optimism make us complacent. The general public's perceptions of women in business leadership and equal pay may, therefore, be a double-edged sword. However, the reality is that women in the workplace and the boardroom have not seen much of an improvement, and we have even further to go to address gaps in ethnic diversity. To ensure women succeed, business leaders need to take a critical look at what is impacting progression and performance of women in the workplace, including burdens from outside the workplace. Hopefully, bosses' apparent commitment to boardroom diversity is a sign of
better things to come.
Katherine Shipton
Understanding Society: It's a Woman's World
Ipsos MORI, part of the Ipsos Group, is a leading UK research company with global reach. We specialise in brand communication, advertising and media research; consumer, retail & shopper and healthcare research; customer and employee relationship management research; and social & political and reputation research.
Headquarter office
3 Thomas More Square
London, E1W 1YW
© 2019–2021 Ipsos | Privacy


So, How About Those Uniforms?
In their first game after the All-Star break, the Golden State Warriors busted out some fancy new duds in celebration of Chinese New Year. The sleek slate uniforms feature red and gold trim, the word for "Warrior" in Chinese characters, and an octagonal sleeve patch with a prancing goat, the new year's presiding animal sign. These special jerseys make their fourth and final appearance of the season tomorrow night, when the team holds official festivities at Oracle Arena while taking on the Milwaukee Bucks.
How are fans reacting to these uniforms? Let's explore a sampling of hypothetical perspectives.
That's valid, but also kind of boring. There's a cliché that we're all just rooting for laundry — so why not take a closer look at the uniforms?
Total nonsense, of course. But if you're superstitious, allow me to direct your attention to a couple alarming details. The Warriors logo highlights the eastern span of the Bay Bridge, a $6.5 billion architectural marvel that opened less than two years ago — and whose various pieces have been cracking, corroding, and leaking ever since. If that symbolism worries you, consider one of the team's taglines, "Warriors Ground," which usually gets depicted with a web of fissures running within or underneath the font, as if portending the Bay Area's next catastrophic earthquake, or Steph Curry's next catastrophic ankle injury. Golden State's marketing department has an obvious karmic death wish.
You mean the one without sleeves? I'm with you on that! People in the Bay Area pride themselves on game-changing innovation, but whoever came up with the idea of putting sleeves on a basketball jersey, well, they chucked up a big fat airball. But aside from the issue of shoulder exposure, you won't find me clamoring to bring back any jerseys of yesteryear. Most of the old motifs — much like the words "Golden State" — disguise the fact that the Warriors play in Oakland. There's that one logo with a star covering a sizable chunk of Northern California; that might be a more appropriate image for the Sacramento Kings, since they're actually in the state capital. And then you have the popular throwback trolley car jerseys; those remind us that the team used to play in San Francisco, and that ownership plans to yank them back over there again soon. What about Thunder, you ask? You can forget him — Russell Westbrook buried his body somewhere out in the Oklahoma Panhandle.
Vera Wang is an important designer, right? When it comes to fashion, I have no clue; "Project Runway" could be a show about airplane landings for all I know. I'm essentially stealing the above quote from Jacobim Mugatu, the evil fashion mogul from the movie "Zoolander," my primary point of reference for the world of couture. It was either that quote or "I feel like I'm taking crazy pills!" — a good Mugatu line to use if you think the jerseys are wack. I could honestly go either way.
You know what, Rockets fans? Your main guy said the Dubs aren't that good. So how did that season series sweep taste? Like Yao Ming's wine? No, because Yao Ming makes his wine in the Bay Area. I think the flavor on your tongue is four games' worth of bitter disappointment. Go back to the suburbs.
1) I'm getting mixed messages on whether "goat" is really the preferred nomenclature in this instance. Signs around Oakland Chinatown have told me to celebrate the year of the sheep. My Wells Fargo ATM has been pushing "ram" at me. Discussions with my friends have not clarified the matter.
2) I'm a dragon. My animal sign will barbecue your animal sign and eat it for lunch.
Look, I'm not going to judge these kinds of missteps too harshly, so long as they come from a place of respect and curiosity. My hope is that, when I hear someone say something uninformed or even offensive, I have the poise and presence of mind to politely broaden their worldview. Besides, I know I've said some dumb things in the past, and will certainly say some dumb things in the future. I've probably said some dumb things in this very post. No one's perfect, and folks gotta learn somehow, right?
I realize that ignorance and racism overlap, but I think it's worth differentiating between the two when malicious intent is involved. It's a lot harder to engage with hatred, or to shrug it off. All I can really say is, I'm just glad it's not the year of the dog, if you know what I mean. That's going to save us some grief.
Say what you will about pandering and tokenism, but I dig that the Warriors stepped up like this. Although I'm upset that the organization, the league, and pro sports overall have been gradually shutting out the common fan, I would like to enjoy this gesture, and take it as one of good will. Sometimes, it feels nice to let go of your cynicism and enjoy the show.
Other times, it feels right to hold tight to your cynicism, clutching it close to your chest like a copy of the "Communist Manifesto" while you watch the show between epic eye rolls of contempt. It's true, teams know they can make a quick buck by switching up their jerseys for special occasions. They don't even need to find a holiday to celebrate — a basic color scheme change will coax in streams of cash. Just ask that lady in the pink Red Sox hat.
Learn to stop worrying and love this new reality. Chairman Mao is dead and gone; Stephon Marbury took his place. At this very moment, Harrison Barnes is brushing up on his Mandarin. NBA Commissioner Adam Silver will one day rule the world. So get in his good graces now and go buy yourself some merchandise.


Our Chicago brain injury lawyers are very familiar with the well-known developmental brain disorder known as autism. Over the past several decades awareness about the many variations of this condition has increased steadily. More and more families continue to be affected by the brain condition, leading many researchers scrambling to better understand what causes it and how it can be prevented. According to PubMed Health, autism affects the development of the brain areas that control social and communication skills. As a result, symptoms are usually not seen until social and communication skills are first noticed, when children are one and a half to three years old. The U.S. Centers for Disease Control and Prevention (CDC) reports that autism is more commonly found in males than females, with upwards of four times as many boys suffering than girls.
Medical researchers are actively working to nail down the causes but as of yet nothing conclusive has been proven. It is known, however, that abnormal brain biology and brain chemistry functions are involved. Most suspect that a range of other factors combine to create the disorder. For one thing, genetics seem to play some role. Studies examining twins have found that identical twins are far more likely than fraternal twins or siblings to experience autism. Researchers have a variety of studies underway aimed at better understanding the various other causes of autism.
For example, this week the Health Jockey discussed a new study on the topics which was just published in the Proceedings of the National Academy of Sciences. The research involved the effect of anti-depressants given during brain developmental stages on the resulting offspring. Down the road the results may lead to changes in the medications taken by expecting mothers or mothers trying to have a baby. The research was a joint effort between researchers at the University of Mississippi Centre and University of California. What they found was that rats which were given certain anti-depressants during particular phases of brain development eventually displayed problems like those faced by those suffering from autism. The drugs in question are known as selective serotonin reuptake inhibitors (SSRIs). One of the researchers involved in this latest effort believes that taking these during conception may increase risk of autism development. However, it is too early to yet make any concrete determinations.
To arrive at these results, the study used nearly 200 rats, exposing them to SSRIs during certain periods of brain development which would be similar to the first trimester and infancy of a human. The drug treatments lasted for two weeks, beginning eight days after their birth. The rats were then monitored and compared with a control group to determine the consequences of the drug use. That observation revealed that those rats given the SSRIs were less social and less playful than the control group counterparts. Also, this effect was more commonly seen in male rats-suggestive of the same characteristics of autism in humans. While encouraging, this research is just the tip of the iceberg. Those involved explained that "this study is a starting point and a lot more research needs to be done." The next step, say the researchers, is examining human SSRI use. In particular, researchers plan on analyzing possible consequences of these drug uses in certain doses and at certain times to determine if any connection to brain problems, such as autism, can be seen.
Our Chicago personal injury attorneys our proud to help individuals and families who have suffered harm in a variety of ways, from car accidents and medical malpractice to birth injuries and preventable brain accidents. Obviously not all injuries are the result of the preventable negligence of others. Yet, sadly in many more cases than most realize, if others had acted carefully on the road, in the hospital room, or elsewhere, a particularly serious injury may have been avoided. Also, as medical knowledge grows and more information is discovered related to the causes of certain problems, including developmental brain injuries like autism, then it will become necessary for those in a position to prevent the resultant harm take steps which may help lower the risk of the problem occurring.


text:
Home > Our Work > Advocacy > LGBTQ Refugee Project
LGBTQ Refugee Project
CLGS is partnering with local bay area congregations and community organizers to develop a congregation-based support system for LGBTQ refugees and asylees in the Bay Area. We would like to invite opening and affirming congregations to get involved by providing basic accompaniment for refugees including support in finding housing, employment, and building community networks. You can also help us raise awareness about the need for improved policies and services to help refugees rebuild their lives in the U.S.
In addition to seeking congregational support, CLGS is researching and exploring how to expand our mission to advocate for LGBTQ issues globally. This involves discovering ways in which CLGS can serve as a strategic facilitator or collaborator with other faith-based and LGBTQ organizations on immigration justice and international human rights issues effecting sexual and gender minorities.
Included in this endeavor is researching and exploring the needs of the international LGBTQ community in the SF Bay Area, especially LGBTQ refugees from outside the United States.
Liberating Religious Liberty Campaign
Ending Conversion Therapy Campaign
52 Ways #20: Encourage and Support HIV Testing
Check out our January 2021 e-newsletter!
Our 2020-2021 Trans Seminarian Cohort!
Please make a donation to the CLGS Annual Fund.


text:
Could your startup use $1.2 million from some of the world's most successful entrepreneurs? You betcha!
Most Houston entrepreneurs know about the Grand Order Of Successful Entrepreneurs (GOOSE) Society—a group of uber-successful entrepreneurs who banded together in 2005 to provide angel investment and support to startups. But over time, as their "investments" have matured, their role is changing.
Samantha Lewis is Director of The GOOSE Society Venture Group, a super angel investment group of venture capital and private equity investors.
More about Samantha Lewis
Samantha Lewis on LinkedIn
Follow Samantha Lewis on Twitter
GOOSE Society on LinkedIn
Learn more about GOOSE Society