text:
/*
  \class SmWellLogKit SmallChange/nodekits/SmWellLogKit.h
  \brief The SmWellLogKit class is used to visualize wells.

*/

/*!
  \var SoSFFloat SmWellLogKit::undefVal
  The value that is used for specifying undefined curve data.
  Default value is -999.25.
*/

/*!
  \var SoSFString SmWellLogKit::name

  A user-specified name for the well. If set, will be displayed at the
  top of the value information tooltip.
*/

/*!
  \var SoMFVec3d SmWellLogKit::wellCoord
  The absolute (UTM) positions of each well position.
*/

/*!
  \var SoMFString SmWellLogKit::curveNames

  The names for each curve in the well log data. The first value
  should be the depth.

*/

/*!
  \var SoMFString SmWellLogKit::curveDescription

  The description for each curve in the well log data.

*/

/*!
  \var SoMFString SmWellLogKit::curveUnits

  The unit for each curve in the well log. Will be used as textual
  information in the tooltip.
*/

/*!
  \var SoMFFloat SmWellDataLogKit::curveData

  The raw well log data. Each log position will first have a depth
  value, then the rest of the curves values, repeated for each log
  position.
*/

/*!
  SoSFFloat SmWellLogKit::leftSize

  The (maximum) size of the left curve visualization.

*/

/*!
  SoSFFloat SmWellLogKit::rightSize

  The (maximum) size of the right curve visualization.

*/

/*!
  SoSFInt32 SmWellLogKit::leftCurveIndex

  The curve index of the left curve. Is used to select the curve on
  the left side of the wel. Use -1 to disable.
*/

/*!
  SoSFInt32 SmWellLogKit::rightCurveIndex

  The curve index of the right curve. Is used to select the curve on
  the right side of the well. Use -1 to disable.

*/

/*!
  SoSFColor SmWellLogKit::leftColor

  The color of the left curve.
*/

/*!
  SoSFColor SmWellLogKit::rightColor

  The color of the right curve.
*/

/*!
  SoSFBool SmWellLogKit::leftUseLog

  Set to TRUE to use a logarithmic function for visualizing the left curve.
*/

/*!
  SoSFBool SmWellLogKit::rightUseLog;

  Set to TRUE to use a logarithmic function for visualizing the right curve.
*/

/*!
  SoSFFloat SmWellLogKit::lodDistance1

  The distance where the well will be rendered as a line, not a cylinder.
*/

/*!
  SoSFFloat SmWellLogKit::lodDistance2

  The distance where the well will not be rendered.
*/

/*!
  SoSFFloat SmWellLogKit::wellRadius

  The radius of the well bore.
*/

/*!
  SoSFFloat SmWellLogKit::wellRadius

  The color of the well bore.
*/

/*!
  SoMFString SmWellLogKit::topsNames

  A list of "tops" strings that should be displayed along the well
  bore at the depths given in topsDepths.
*/

/*!
  SoMFFloat SmWellLogKit::topsDepths

  The list of depths where the topsNames should be displayed.
*/

/*!
  SoSFColor SmWellLogKit::topsColor

  The color of the topsNames strings.
*/

/*!
  SoSFColor SmWellLogKit::topsSize

  The fonts size (=world space height of characters) the topsNames strings.
*/

/*!
  SoSFFloat SmWellLogKit::leftCurveMin

  Clamp left curve values. Clamping will be done when leftCurveMin < leftCurveMax.
  Default value is 1.0 (no clamping, since max is 0.0)
*/

/*!
  SoSFFloat SmWellLogKit::leftCurveMax

  Clamp left curve values. Clamping will be done when leftCurveMin < leftCurveMax.
  Default value is 0.0 (no clamping, since min is 1.0)
*/

/*!
  SoSFFloat SmWellLogKit::rightCurveMin

  Clamp right curve values. Clamping will be done when leftCurveMin < leftCurveMax.
  Default value is 1.0 (no clamping, since max is 0.0)

*/

/*!
  SoSFFloat SmWellLogKit::rightCurveMax

  Clamp right curve values. Clamping will be done when leftCurveMin < leftCurveMax.
  Default value is 0.0 (no clamping, since min is 1.0)
*/

#include "SmWellLogKit.h"
#include <SmallChange/nodes/UTMPosition.h>
#include <SmallChange/nodes/SoLODExtrusion.h>
#include <SmallChange/nodekits/SmTooltipKit.h>
#include <Inventor/actions/SoGetBoundingBoxAction.h>
#include <Inventor/actions/SoGetMatrixAction.h>
#include <Inventor/actions/SoRayPickAction.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoHandleEventAction.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/actions/SoCallbackAction.h>
#include <Inventor/actions/SoGetPrimitiveCountAction.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoLOD.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoScale.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/nodes/SoShapeHints.h>
#include <Inventor/nodes/SoBaseColor.h>
#include <Inventor/nodes/SoPackedColor.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoMaterialBinding.h>
#include <Inventor/nodes/SoPickStyle.h>
#include <Inventor/nodes/SoIndexedFaceSet.h>
#include <Inventor/nodes/SoIndexedLineSet.h>
#include <Inventor/nodes/SoLineSet.h>
#include <Inventor/nodes/SoPolygonOffset.h>
#include <Inventor/nodes/SoInfo.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/nodes/SoCamera.h>
#include <Inventor/nodes/SoCallback.h>
#include <Inventor/nodes/SoFontStyle.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoTranslation.h>
#include <Inventor/nodes/SoRotation.h>
#include <Inventor/nodes/SoText3.h>
#include <Inventor/nodes/SoText2.h>
#include <Inventor/nodes/SoSwitch.h>
#include <Inventor/VRMLnodes/SoVRMLBillboard.h>
#include <Inventor/sensors/SoOneShotSensor.h>
#include <Inventor/sensors/SoFieldSensor.h>
#include <Inventor/elements/SoCacheElement.h>
#include <Inventor/elements/SoViewVolumeElement.h>
#include <Inventor/elements/SoModelMatrixElement.h>
#include <Inventor/elements/SoDrawStyleElement.h>
#include <Inventor/elements/SoSwitchElement.h>
#include <Inventor/elements/SoCacheElement.h>
#include <Inventor/events/SoMouseButtonEvent.h>
#include <Inventor/events/SoLocation2Event.h>
#include <Inventor/SoPickedPoint.h>
#include <Inventor/details/SoLineDetail.h>
#include <Inventor/engines/SoCalculator.h>
#include <cfloat>
#include <cstring>

// struct used for storing data for each depth value
typedef struct {
  SbVec3f pos;
  SbColor col;
  double mdepth;  // measured depth
  double tvdepth; // true vertical depth
  double left;  // curve data for the left side
  double right; // curve data for the right side
  int realidx;
} sm_well_pos;

class well_tooltip_info {
public:
  well_tooltip_info(const char * name, const int idx, const int num, const float * val,
                    const char ** text) {
    this->name = new char[strlen(name)+1];
    strcpy(this->name, name);
    this->curveidx = idx;
    this->num = num;
    this->data = new float[num];
    memcpy(this->data, val, num*sizeof(float));
    this->text = new char*[num];
    for (int i = 0; i < num; i++) {
      int len = strlen(text[i]);
      this->text[i] = new char[len+1];
      strcpy(this->text[i], text[i]);
    }
  }
  ~well_tooltip_info() {
  }
public:
  char * name;
  int curveidx;
  int num;
  float * data;
  char ** text;
};

class SmWellLogKitP {
public:
  SmWellLogKitP(SmWellLogKit * master)
    : master(master) { }

  SmWellLogKit * master;

  // FIXME: consider dict
  SbList <SbName> cm_name;
  SbList <uint32_t> cm_col;

  SbList <float> leftoffset;
  SbList <float> rightoffset;

  SbList <sm_well_pos> poslist;
  SbVec3f axis;
  SbVec3f prevaxis;
  SbBool processingoneshot;

  SoCalculator *radiusEngine;
  SbList <well_tooltip_info*> extra_tooltip_info;

  uint32_t find_col(const SbName & name);
  int find_colidx(const SbName & name);
  void updateList(void);
  void updateName() { }
  void buildGeometry(void);
  void buildTopsSceneGraph(void);
  void generateFaces(const SbVec3f & axis);
  void setLithOrFluid(const SbList <double> & limits,
                      const SbList <SbName> & names,
                      const SbBool islith);
  void convertDepth(const SbList <double> & data);
  static void callback_cb(void * userdata, SoAction * action);

  SoOneShotSensor * oneshot;

  static void oneshot_cb(void * closure, SoSensor * s);
};

SO_KIT_SOURCE(SmWellLogKit);

#define PRIVATE(obj) (obj)->pimpl

SmWellLogKit::SmWellLogKit(void)
{
  PRIVATE(this) = new SmWellLogKitP(this);
  PRIVATE(this)->axis = SbVec3f(1.0f, 0.0f, 0.0f);
  PRIVATE(this)->prevaxis = SbVec3f(0.0f, 0.0f, 0.0f);
  PRIVATE(this)->oneshot = new SoOneShotSensor(SmWellLogKitP::oneshot_cb, PRIVATE(this));
  PRIVATE(this)->oneshot->setPriority(1);
  PRIVATE(this)->processingoneshot = FALSE;

  SO_KIT_CONSTRUCTOR(SmWellLogKit);

  SO_KIT_ADD_FIELD(undefVal, (-999.25));
  SO_KIT_ADD_FIELD(name,(""));
  SO_KIT_ADD_FIELD(wellCoord, (0.0, 0.0, 0.0));
  SO_KIT_ADD_FIELD(wellColor, (0.8f, 0.8f, 0.8f));

  SO_KIT_ADD_FIELD(curveNames, (""));
  SO_KIT_ADD_FIELD(curveDescription, (""));
  SO_KIT_ADD_FIELD(curveUnits, (""));
  SO_KIT_ADD_FIELD(curveData, (0.0f));
  SO_KIT_ADD_FIELD(leftSize, (50.0f));
  SO_KIT_ADD_FIELD(rightSize, (50.0f));

  SO_KIT_ADD_FIELD(leftCurveIndex, (-1));
  SO_KIT_ADD_FIELD(rightCurveIndex, (-1));

  SO_KIT_ADD_FIELD(leftUseLog, (FALSE));
  SO_KIT_ADD_FIELD(rightUseLog, (FALSE));

  SO_KIT_ADD_FIELD(lodDistance1, (50000.0f));
  SO_KIT_ADD_FIELD(lodDistance2, (100000.0f));

  SO_KIT_ADD_FIELD(wellRadius, (1.0f));
  SO_KIT_ADD_FIELD(leftColor, (0.3f, 0.6f, 0.8f));
  SO_KIT_ADD_FIELD(rightColor, (0.3f, 0.6f, 0.8f));

  SO_KIT_ADD_FIELD(topsDepths, (0.0f));
  SO_KIT_ADD_FIELD(topsNames, (NULL));
  SO_KIT_ADD_FIELD(topsColor, (0.8f, 0.4f, 0.4f));
  SO_KIT_ADD_FIELD(topsSize, (10.0f));

  SO_KIT_ADD_FIELD(leftCurveMin, (1.0f));
  SO_KIT_ADD_FIELD(leftCurveMax, (0.0f));

  SO_KIT_ADD_FIELD(rightCurveMin, (1.0f));
  SO_KIT_ADD_FIELD(rightCurveMax, (0.0f));

  this->wellCoord.setNum(0);
  this->wellCoord.setDefault(TRUE);
  this->curveNames.setNum(0);
  this->curveNames.setDefault(TRUE);
  this->curveDescription.setNum(0);
  this->curveDescription.setDefault(TRUE);
  this->curveData.setNum(0);
  this->curveData.setDefault(TRUE);
  this->curveUnits.setNum(0);
  this->curveUnits.setDefault(TRUE);
  this->topsDepths.setNum(0);
  this->topsDepths.setDefault(TRUE);
  this->topsNames.setNum(0);
  this->topsNames.setDefault(TRUE);

  SO_KIT_ADD_CATALOG_ENTRY(topSeparator, SoSeparator, FALSE, this, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(tooltip, SmTooltipKit, FALSE, topSeparator, utm, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(utm, UTMPosition, FALSE, topSeparator, transform, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(transform, SoTransform, FALSE, topSeparator, topLod, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(topLod, SoLOD, FALSE, topSeparator, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(topLodGroup, SoSeparator, FALSE, topLod, topInfo, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(shapeHints, SoShapeHints, FALSE, topLodGroup, wellBaseColor, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(wellBaseColor, SoBaseColor, FALSE, topLodGroup, wellDrawStyle, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(wellDrawStyle, SoDrawStyle, FALSE, topLodGroup, well, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(well, SoLODExtrusion, FALSE, topLodGroup, wellNameSep, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(wellNameSep, SoSeparator, FALSE, topLodGroup, lightModel, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(wellNameColor, SoBaseColor, FALSE, wellNameSep, wellName, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(wellName, SoText2, FALSE, wellNameSep, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(lightModel, SoLightModel, FALSE, topLodGroup, pickStyle, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(pickStyle, SoPickStyle, FALSE, topLodGroup, lod, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(lod, SoLOD, FALSE, topLodGroup, topsSep, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(lodSeparator, SoSeparator, FALSE, lod, info, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(callbackNode, SoCallback, FALSE, lodSeparator, materialBinding, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(materialBinding, SoMaterialBinding, FALSE, lodSeparator, faceSetColor, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(faceSetColor, SoPackedColor, FALSE, lodSeparator, coord, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(coord, SoCoordinate3, FALSE, lodSeparator, drawStyleSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(drawStyleSwitch, SoSwitch, FALSE, lodSeparator, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(lineSet, SoIndexedLineSet, FALSE, drawStyleSwitch, faceSet, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(faceSet, SoIndexedFaceSet, FALSE, drawStyleSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(info, SoInfo, FALSE, lod, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(topsSep, SoSeparator, FALSE, topLodGroup, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(topsFontStyle, SoFontStyle, FALSE, topsSep, topsBaseColor, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(topsBaseColor, SoBaseColor, FALSE, topsSep, topsList, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(topsList, SoSeparator, FALSE, topsSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(topInfo, SoInfo, FALSE, topLod, "", FALSE);

  SO_KIT_INIT_INSTANCE();

  SoDrawStyle * wds = (SoDrawStyle*) this->getAnyPart("wellDrawStyle", TRUE);
  wds->lineWidth = 3.0;

  SoText2 * welltext = (SoText2*) this->getAnyPart("wellName", TRUE);
  welltext->string.connectFrom(&this->name);

  SoBaseColor * wellnamecolor = (SoBaseColor*) this->getAnyPart("wellNameColor", TRUE);
  wellnamecolor->rgb = SbColor(0.0f, 0.0f, 0.0f);

  // initialize parts to default values
  SoShapeHints * sh = (SoShapeHints*) this->getAnyPart("shapeHints", TRUE);
  sh->vertexOrdering = SoShapeHints::CLOCKWISE;
  sh->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
  sh->faceType = SoShapeHints::CONVEX;

  SoLODExtrusion * well = (SoLODExtrusion*) this->getAnyPart("well", TRUE);
  well->ccw = TRUE;
  well->lodDistance1.connectFrom(&this->lodDistance1);
  well->radius.connectFrom(&this->wellRadius);

  SoPickStyle * ps = (SoPickStyle*) this->getAnyPart("pickStyle", TRUE);
  ps->style = SoPickStyle::UNPICKABLE;

  SoMaterialBinding * mb = (SoMaterialBinding*) this->getAnyPart("materialBinding", TRUE);
  mb->value = SoMaterialBinding::PER_FACE_INDEXED;

  SoLightModel * lm = (SoLightModel*) this->getAnyPart("lightModel", TRUE);
  lm->model = SoLightModel::BASE_COLOR;

  SoLOD * toplod = (SoLOD*) this->getAnyPart("topLod", TRUE);
  toplod->range.connectFrom(&this->lodDistance2);

  SoLOD * facelod = (SoLOD*) this->getAnyPart("lod", TRUE);
  facelod->range.connectFrom(&this->lodDistance1);

  SoCallback * cb = (SoCallback*) this->getAnyPart("callbackNode", TRUE);
  cb->setCallback(SmWellLogKitP::callback_cb, PRIVATE(this));

  SoSwitch * sw = (SoSwitch*) this->getAnyPart("drawStyleSwitch", TRUE);
  // use SoSwitchElement to decide which child to traverse
  sw->whichChild = SO_SWITCH_INHERIT;

  //FIXME: Connect from new fields (kintel)
  SoBaseColor *topsBaseColor = (SoBaseColor *)this->getAnyPart("topsBaseColor", TRUE);
  topsBaseColor->rgb.connectFrom(&this->topsColor);

  SoFontStyle *topsFontStyle = (SoFontStyle *)this->getAnyPart("topsFontStyle", TRUE);
  topsFontStyle->size.connectFrom(&this->topsSize);

  PRIVATE(this)->radiusEngine = new SoCalculator;
  PRIVATE(this)->radiusEngine->ref();
  PRIVATE(this)->radiusEngine->a.connectFrom(&this->wellRadius);
  PRIVATE(this)->radiusEngine->b.connectFrom(&this->topsSize);
  PRIVATE(this)->radiusEngine->expression.set1Value(0, "oa = a*1.2");
  PRIVATE(this)->radiusEngine->expression.set1Value(1, "oA[0] = a*1.4");
  PRIVATE(this)->radiusEngine->expression.set1Value(2, "oA[1] = -b/2");
  PRIVATE(this)->radiusEngine->expression.set1Value(3, "oA[2] = a*1.2");

}

SmWellLogKit::~SmWellLogKit(void)
{
  for (int i = 0; i < PRIVATE(this)->extra_tooltip_info.getLength(); i++) {
    delete PRIVATE(this)->extra_tooltip_info[i];
  }

  PRIVATE(this)->radiusEngine->unref();
  delete PRIVATE(this)->oneshot;
  delete PRIVATE(this);
}

void
SmWellLogKit::initClass(void)
{
  static int first = 1;
  if (first) {
    first = 0;
    SO_KIT_INIT_CLASS(SmWellLogKit, SoBaseKit, "BaseKit");
  }
}

void
SmWellLogKit::GLRender(SoGLRenderAction * action)
{
  // use SoSwitchElement to control whether we should render with the
  // faceset or the lineset
  SoState * state = action->getState();
  if (PRIVATE(this)->oneshot->isScheduled()) {
    SoCacheElement::invalidate(state);
    return;
  }
  state->push();
  if (SoDrawStyleElement::get(state) == SoDrawStyleElement::LINES) {
    SoSwitchElement::set(state, this, 0);
  }
  else {
    SoSwitchElement::set(state, this, 1);
  }
  inherited::GLRender(action);
  state->pop();
}

void
SmWellLogKit::callback(SoCallbackAction * action)
{
  SoState * state = action->getState();
  state->push();
  SoSwitchElement::set(state, this, 1);
  inherited::callback(action);
  state->pop();
}

void
SmWellLogKit::getMatrix(SoGetMatrixAction * action)
{
  SoState * state = action->getState();
  state->push();
  SoSwitchElement::set(state, this, 1);
  inherited::getMatrix(action);
  state->pop();
}

void
SmWellLogKit::rayPick(SoRayPickAction * action)
{
  SoState * state = action->getState();
  state->push();
  SoSwitchElement::set(state, this, 1);
  inherited::rayPick(action);
  state->pop();
}

void
SmWellLogKit::search(SoSearchAction * action)
{
  SoState * state = action->getState();
  state->push();
  SoSwitchElement::set(state, this, 1);
  inherited::search(action);
  state->pop();
}

void
SmWellLogKit::getPrimitiveCount(SoGetPrimitiveCountAction * action)
{
  SoState * state = action->getState();
  // state->push();
  SoSwitchElement::set(state, this, 1);
  inherited::getPrimitiveCount(action);
  //state->pop();
}

void
SmWellLogKit::getBoundingBox(SoGetBoundingBoxAction * action)
{
  SoState * state = action->getState();
  if (PRIVATE(this)->oneshot->isScheduled()) {
    SoCacheElement::invalidate(state);
    return;
  }
  state->push();
  SoSwitchElement::set(state, this, 1);
  // the kit has changed but the sensor has not triggered
  // yet. Calculate manually and unschedule() so that we get the
  // correct bounding box.
  inherited::getBoundingBox(action);
  state->pop();
}

void
SmWellLogKit::handleEvent(SoHandleEventAction * action)
{
  // the kit has changed but the sensor has not triggered
  // yet. Calculate manually and unschedule() so that we get the
  // correct bounding box.
  if (PRIVATE(this)->oneshot->isScheduled()) {
    return;
  }

  SmTooltipKit * tooltip = (SmTooltipKit*)this->getAnyPart("tooltip", FALSE);
  if (!tooltip) return;

  const SoEvent * event = action->getEvent();

  SbBool handled = FALSE;

  if (SO_MOUSE_RELEASE_EVENT(event, BUTTON1)) {
    if (tooltip->isActive.getValue()) {
      tooltip->isActive = FALSE;
      action->releaseGrabber();
      action->setHandled();
      return;
    }
  }

  // FIXME: investigate SoLocation2Event to see if left mouse button
  // has been released. Don't trust that we get a
  // SoMouseButtonReleaseEvent. pederb, 2003-10-16

  if ((!tooltip->isActive.getValue() && SO_MOUSE_PRESS_EVENT(event, BUTTON1)) ||
      (tooltip->isActive.getValue() && event->isOfType(SoLocation2Event::getClassTypeId()))) {

    const SoPickedPoint * pp = action->getPickedPoint();
    SoSeparator * topsep = (SoSeparator*) this->getAnyPart("topSeparator", TRUE);

    if (pp) {
      SoFullPath * path = (SoFullPath*) pp->getPath();
      int idx = path->findNode(topsep);
      if (idx >= 0) {
        const SoDetail * detail = pp->getDetail();
        if (detail && detail->isOfType(SoLineDetail::getClassTypeId())) {
          idx = this->findPickIdx(pp->getObjectPoint());
          if (this->setTooltipInfo(idx, tooltip)) {
            handled = TRUE;
            tooltip->setPickedPoint(pp, action->getViewportRegion());
            tooltip->isActive = TRUE;
            action->setGrabber(this);
          }
        }
      }
    }
  }
  if (handled) action->setHandled();
  else inherited::handleEvent(action);
}

SbBool
SmWellLogKit::readInstance(SoInput * in, unsigned short flags)
{
  SbBool ret = inherited::readInstance(in, flags);
  if (ret) {
    // only really needed to load old files...
    this->connectNodes(); // make connections from fields to nodes
  }
  return ret;
}

// linear search for depth index. Optimize?
int
SmWellLogKit::findPickIdx(const SbVec3f & pos) const
{
  int n = PRIVATE(this)->poslist.getLength();
  for (int i = 0; i < n; i++) {
    if (pos[2] > PRIVATE(this)->poslist[i].pos[2]) return i;
  }
  return n-1;
}

// fill in tooltip info for a picked depth index
SbBool
SmWellLogKit::setTooltipInfo(const int idx, SmTooltipKit * tooltip)
{
  if (idx < 0 || idx >= PRIVATE(this)->poslist.getLength()) return FALSE;

  const sm_well_pos & pos = PRIVATE(this)->poslist[idx];

  SbString l("UNDEFINED");
  SbString r("UNDEFINED");

  float undefval = this->undefVal.getValue();

  if (pos.left != undefval) {
    l.sprintf("%g", pos.left);
  }
  if (pos.right != undefval) {
    r.sprintf("%g", pos.right);
  }

  // Reset to avoid old cruft showing up. Multifield will expand
  // automatically on the set1Value() calls below.
  tooltip->description.setNum(0);
  int numcurves = this->getNumCurves();
  SbString str;

  unsigned int stridx = 0;
  if (this->name.getValue() != "") {
    tooltip->description.set1Value(stridx++, this->name.getValue());
  }
  for (int i = 0; i < PRIVATE(this)->extra_tooltip_info.getLength(); i++) {
    well_tooltip_info * info = PRIVATE(this)->extra_tooltip_info[i];
    int fidx = pos.realidx * numcurves + info->curveidx;

    if (fidx < this->curveData.getNum()) {
      float val = this->curveData[fidx];
      for (int j = 0; j < info->num; j++) {
        if (fabs(info->data[j]-val) < 0.5f) {
          str.sprintf("%s: %s",
                      info->name, info->text[j]);
          tooltip->description.set1Value(stridx++, str);
          break;
        }
      }
    }
  }
  str.sprintf("Depth: %g", pos.mdepth);
  tooltip->description.set1Value(stridx++, str);
  str.sprintf("TVDSS: %g", pos.tvdepth);
  tooltip->description.set1Value(stridx++, str);

  const int lidx = this->leftCurveIndex.getValue();
  const int ridx = this->rightCurveIndex.getValue();

  if (lidx >= 0) {
    str.sprintf("%s: %s",
                this->curveNames[lidx].getString(), l.getString());
    tooltip->description.set1Value(stridx++, str);
  }
  if (ridx >= 0) {
    str.sprintf("%s: %s",
                this->curveNames[ridx].getString(), r.getString());
    tooltip->description.set1Value(stridx++, str);
  }

  return TRUE;
}

void
SmWellLogKit::connectNodes(void)
{
  SoLODExtrusion * well = (SoLODExtrusion*) this->getAnyPart("well", TRUE);
  well->lodDistance1.connectFrom(&this->lodDistance1);
  well->radius.connectFrom(&this->wellRadius);

  SoLOD * toplod = (SoLOD*) this->getAnyPart("topLod", TRUE);
  toplod->range.connectFrom(&this->lodDistance2);

  SoLOD * facelod = (SoLOD*) this->getAnyPart("lod", TRUE);
  facelod->range.connectFrom(&this->lodDistance1);

  SoCallback * cb = (SoCallback*) this->getAnyPart("callbackNode", TRUE);
  cb->setCallback(SmWellLogKitP::callback_cb, PRIVATE(this));
}

int
SmWellLogKit::getNumCurves(void) const
{
  return this->curveNames.getNum();
}

int
SmWellLogKit::getNumCurveValues(void) const
{
  int num = this->getNumCurves();
  if (num) {
    return this->curveData.getNum() / num;
  }
  return 0;
}

// returns the depth value for a depth index
float
SmWellLogKit::getDepth(const int idx) const
{
  // FIXME: assumes depth is always first. Add depthIndex field?
  int num = this->getNumCurves();
  if (num) {
    int fidx = idx*num;
    assert(fidx < this->curveData.getNum());
    if (fidx < this->curveData.getNum()) {
      return this->curveData[fidx];
    }
  }
  return 0.0f;
}

// returns the left curve value for a depth index
float
SmWellLogKit::getLeftCurveData(const int idx) const
{
  int num = this->getNumCurves();
  if (num && this->leftCurveIndex.getValue() >= 0) {
    int fidx = idx*num + this->leftCurveIndex.getValue();
    assert(fidx < this->curveData.getNum());
    if (fidx < this->curveData.getNum()) {
      float minv = this->leftCurveMin.getValue();
      float maxv = this->leftCurveMax.getValue();
      if (maxv > minv) {
        return SbClamp(this->curveData[fidx], minv, maxv);
      }
      return this->curveData[fidx];
    }
  }
  return this->undefVal.getValue();
}

// returns the right curve value for a depth index
float
SmWellLogKit::getRightCurveData(const int idx) const
{
  int num = this->getNumCurves();
  if (num && this->rightCurveIndex.getValue() >= 0) {
    int fidx = idx*num + this->rightCurveIndex.getValue();
    assert(fidx < this->curveData.getNum());
    if (fidx < this->curveData.getNum()) {
      float minv = this->rightCurveMin.getValue();
      float maxv = this->rightCurveMax.getValue();
      if (maxv > minv) {
        return SbClamp(this->curveData[fidx], minv, maxv);
      }
      return this->curveData[fidx];
    }
  }
  return this->undefVal.getValue();
}

// overloader to test when stuff changes in the API fields
void
SmWellLogKit::notify(SoNotList * l)
{
  if (!PRIVATE(this)->oneshot->isScheduled() && !PRIVATE(this)->processingoneshot) {
    SoField * f = l->getLastField();
    if (f) {
      SoFieldContainer * c = f->getContainer();
      // test if a field in this nodekit changed, but only trigger on
      // normal fields, not on part fields.
      if (c == this && f->getTypeId() != SoSFNode::getClassTypeId()) {
        // trigger a sensor that will recalculate all internal data
        PRIVATE(this)->oneshot->schedule();
      }
    }
  }
  inherited::notify(l);
}

/*!

  Overloaded to set most node fields to default. The parts in this
  nodekit are mostly internal.

*/
void
SmWellLogKit::setDefaultOnNonWritingFields(void)
{
  SoFieldList fl;
  (void) this->getFields(fl);
  for (int i = 0; i < fl.getLength(); i++) {
    SoField * f = fl[i];
    if (f->isOfType(SoSFNode::getClassTypeId()) &&
        f != &this->transform) {
      f->setDefault(TRUE);
    }
  }
  inherited::setDefaultOnNonWritingFields();
}

void
SmWellLogKit::addTooltipInfo(const char * name,
                             const int curveidx,
                             const int numvalues,
                             const float * data,
                             const char ** datatext)
{
  PRIVATE(this)->extra_tooltip_info.append(new well_tooltip_info(name, curveidx,
                                                                 numvalues,
                                                                 data,
                                                                 datatext));
}

#undef PRIVATE

#define PUBLIC(obj) (obj)->master

uint32_t
SmWellLogKitP::find_col(const SbName & name)
{
  if (name == "left") {
    return PUBLIC(this)->leftColor.getValue().getPackedValue();
  }
  if (name == "right") {
    return PUBLIC(this)->rightColor.getValue().getPackedValue();
  }
  int idx = find_colidx(name);
  if (idx < 0) {
    return 0x4477ccff;
  }
  return cm_col[idx];
}

int
SmWellLogKitP::find_colidx(const SbName & name)
{
  for (int i = 0; i < cm_name.getLength(); i++) {
    if (cm_name[i] == name) return i;
  }
  return -1;
}

void
SmWellLogKitP::callback_cb(void * userdata, SoAction * action)
{
  SmWellLogKitP * thisp = (SmWellLogKitP*) userdata;
  if (action->isOfType(SoGetBoundingBoxAction::getClassTypeId())) {
    SoCacheElement::invalidate(action->getState());
  }
  else if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
    SoState * state = action->getState();
    SoCacheElement::invalidate(state);

    const SbViewVolume & vv = SoViewVolumeElement::get(state);
    SbVec3f Z = vv.getProjectionDirection();
    SbVec3f Y = vv.getViewUp();
    SbVec3f X = Y.cross(Z);

    // make log gfx face the viewer/camera
    SbMatrix m;
    m.makeIdentity();
    m[0][0] = X[0];
    m[0][1] = X[1];
    m[0][2] = X[2];

    m[1][0] = Y[0];
    m[1][1] = Y[1];
    m[1][2] = Y[2];

    m[2][0] = Z[0];
    m[2][1] = Z[1];
    m[2][2] = Z[2];

    // account for model matrix
    m.multRight(SoModelMatrixElement::get(state).inverse());

    SbVec3f axis(1.0f, 0.0f, 0.0f); // FIXME: possible to configure by user?
    m.multDirMatrix(axis, axis);

    axis[2] = 0.0f;
    if (axis == SbVec3f(0.0f, 0.0f, 0.0f)) axis = SbVec3f(1.0f, 0.0f, 0.0f);
    else axis.normalize();

    // FIXME: use an epsilon when comparing here?
    if (axis != thisp->prevaxis) {
      thisp->prevaxis = axis;
      thisp->generateFaces(axis);
    }
  }
}

// generate faces facing the viewer
void
SmWellLogKitP::generateFaces(const SbVec3f & newaxis)
{
  SoCoordinate3 * coord = (SoCoordinate3*) PUBLIC(this)->getAnyPart("coord", TRUE);

  int i, n = this->poslist.getLength();
  coord->point.setNum(3*n);
  SbVec3f * dst = coord->point.startEditing();

  for (i = 0; i < n; i++) {
    dst[n+i] = this->poslist[i].pos + newaxis * this->leftoffset[i];
    dst[2*n+i] = this->poslist[i].pos - newaxis * this->rightoffset[i];
  }
  coord->point.finishEditing();
}

// FIXME: should it be possible to configure the log function?
static double log_func(double val)
{
  if (val < 0.0) return -1.0;
  return log10(1.0 + val);
}

void
SmWellLogKitP::buildGeometry(void)
{
  this->leftoffset.truncate(0);
  this->rightoffset.truncate(0);

  int i, n = this->poslist.getLength();

  double leftmax = -DBL_MIN;
  double rightmax = -DBL_MAX;
  double leftmin = DBL_MAX;
  double rightmin = DBL_MAX;
  double undef = PUBLIC(this)->undefVal.getValue();

  for (i = 0; i < n; i++) {
    double l = this->poslist[i].left;
    double r = this->poslist[i].right;

    if (l != undef) {
      if (l < leftmin) leftmin = l;
      if (l > leftmax) leftmax = l;
    }
    if (r != undef) {
      if (r < rightmin) rightmin = r;
      if (r > rightmax) rightmax = r;
    }
  }

  double leftdiff = leftmax - leftmin;
  double rightdiff = rightmax - rightmin;

  double leftscale = leftdiff ? 1.0 / leftdiff : 1.0;
  double rightscale = rightdiff ? 1.0 / rightdiff : 1.0;

  if (leftdiff && PUBLIC(this)->leftUseLog.getValue()) {
    leftscale = 1.0 / log_func(leftdiff);
  }
  if (rightdiff && PUBLIC(this)->rightUseLog.getValue()) {
    rightscale = 1.0 / log_func(rightdiff);
  }

  leftscale *= PUBLIC(this)->leftSize.getValue() * 0.5;
  rightscale *= PUBLIC(this)->rightSize.getValue() * 0.5;

  int numleft = 0;
  int numright = 0;

  for (i = 0; i < n-1; i++) {
    if (this->poslist[i].left != PUBLIC(this)->undefVal.getValue() &&
        this->poslist[i+1].left != PUBLIC(this)->undefVal.getValue()) numleft++;
    if (this->poslist[i].right != PUBLIC(this)->undefVal.getValue() &&
        this->poslist[i+1].right != PUBLIC(this)->undefVal.getValue()) numright++;
  }

  SoBaseColor *wellBaseColor = (SoBaseColor *) PUBLIC(this)->getAnyPart("wellBaseColor", TRUE);
  wellBaseColor->rgb =
    PUBLIC(this)->wellColor.getNum() ?
    PUBLIC(this)->wellColor[0] : SbColor(0.8f, 0.8f, 0.8f);

  SbList <SbVec3f> redlist(this->poslist.getLength());
  SbList <SbColor> collist(this->poslist.getLength());

  SoLODExtrusion * well = (SoLODExtrusion*) PUBLIC(this)->getAnyPart("well", TRUE);

  SbBool colpersegment = PUBLIC(this)->wellColor.getNum() == PUBLIC(this)->wellCoord.getNum();

  for (i = 0; i < n; i++) {
    if ((i == 0) || (i == n-1)) {
      redlist.append(this->poslist[i].pos);
      if (colpersegment) collist.append(this->poslist[i].col);
    }
    else {
      SbVec3f prev = this->poslist[i-1].pos;
      SbVec3f p = this->poslist[i].pos;
      SbVec3f next = this->poslist[i+1].pos;

      SbVec3f v0 = p - prev;
      SbVec3f v1 = next - p;

      v0.normalize();
      v1.normalize();

      SbBool coldiff = FALSE;
      if (colpersegment) {
        if ((this->poslist[i-1].col != this->poslist[i].col) ||
            (this->poslist[i].col != this->poslist[i+1].col)) {
          coldiff = TRUE;
        }
      }

      // try to reduce lines that are almost straight. 0.00001 is
      // chosen based on experience...
      if (SbAbs(1.0f-v0.dot(v1)) > 0.00001f || coldiff) {
        redlist.append(this->poslist[i].pos);
        if (colpersegment) collist.append(this->poslist[i].col);
      }
    }
  }

  well->spine.setNum(redlist.getLength());
  well->spine.setValues(0, redlist.getLength(), redlist.getArrayPtr());
  well->color.setNum(collist.getLength());
  if (colpersegment) {
    well->color.setValues(0, collist.getLength(), collist.getArrayPtr());
  }

  SoPackedColor * fscol = (SoPackedColor*) PUBLIC(this)->getAnyPart("faceSetColor", TRUE);
  SoCoordinate3 * coord = (SoCoordinate3*) PUBLIC(this)->getAnyPart("coord", TRUE);

  fscol->orderedRGBA.setNum(n*2);
  uint32_t * col = fscol->orderedRGBA.startEditing();

  coord->point.setNum(n * 3);
  SbVec3f * dst = coord->point.startEditing();
  SbVec3f prev;
  for (i = 0; i < n; i++) {
    dst[i] = this->poslist[i].pos;
    prev = dst[i];
    col[i] = find_col(SbName("left"));
    col[i+n] = find_col(SbName("right"));
  }

  for (i = 0; i < n; i++) {
    float l = (float) this->poslist[i].left;
    float r = (float) this->poslist[i].right;

    if (l == undef) {
      this->leftoffset.append(0.0);
    }
    else {
      l -= (float) leftmin;
      if (PUBLIC(this)->leftUseLog.getValue()) {
        l = (float) log_func(l);
      }
      l *= (float) leftscale;
      this->leftoffset.append(l + PUBLIC(this)->leftSize.getValue() * 0.5f);
    }
    if (r == undef) {
      this->rightoffset.append(0.0);
    }
    else {
      r -= (float) rightmin;
      if (PUBLIC(this)->rightUseLog.getValue()) {
        r = (float) log_func(r);
      }
      r *= (float) rightscale;
      this->rightoffset.append(r + PUBLIC(this)->rightSize.getValue() * 0.5f);
    }
  }

  SoIndexedFaceSet * ifs = (SoIndexedFaceSet*) PUBLIC(this)->getAnyPart("faceSet", TRUE);

  ifs->coordIndex.setNum(numleft * 5 + numright * 5);
  int32_t * dsti = ifs->coordIndex.startEditing();

  ifs->materialIndex.setNum(numleft + numright);
  int32_t * dstm = ifs->materialIndex.startEditing();

  for (i = 0; i < n-1; i++) {
    if (this->poslist[i].left != PUBLIC(this)->undefVal.getValue() &&
        this->poslist[i+1].left != PUBLIC(this)->undefVal.getValue()) {

      *dsti++ = i;
      *dsti++ = n+i;
      *dsti++ = n+i+1;
      *dsti++ = i+1;
      *dsti++ = -1;
      *dstm++ = i;
    }
    if (this->poslist[i].right != PUBLIC(this)->undefVal.getValue() &&
        this->poslist[i+1].right != PUBLIC(this)->undefVal.getValue()) {

      *dsti++ = i;
      *dsti++ = i+1;
      *dsti++ = 2*n+i+1;
      *dsti++ = 2*n+i;
      *dsti++ = -1;
      *dstm++ = i+n;
    }
  }

  coord->point.finishEditing();
  ifs->coordIndex.finishEditing();
  ifs->materialIndex.finishEditing();

  SoIndexedLineSet * ils = (SoIndexedLineSet*)
    PUBLIC(this)->getPart("lineSet", TRUE);

  int num = 0;
  if (numleft > 1 && numright > 1) num = numleft + numright + 2;
  else {
    if (numleft > 1) num += numleft;
    if (numright > 1) num += numright;
    num++;
  }

  ils->coordIndex.setNum(num);
  ils->materialIndex.setNum(num);
  dsti = ils->coordIndex.startEditing();
  dstm = ils->materialIndex.startEditing();

  if (numleft > 1) {
    for (i = 0; i < n-1; i++) {
      if (this->poslist[i].left != PUBLIC(this)->undefVal.getValue()) {
        *dsti++ = i + n;
        *dstm++ = i;
      }
    }
    *dsti++ = -1;
    *dstm++ = -1;
  }
  if (numright > 1) {
    for (i = 0; i < n-1; i++) {
      if (this->poslist[i].right != PUBLIC(this)->undefVal.getValue()) {
        *dsti++ = i + 2*n;
        *dstm++ = i + n;
      }
    }
    *dsti++ = -1;
    *dstm++ = -1;
  }

  ils->coordIndex.finishEditing();
  ils->materialIndex.finishEditing();
}

/*!
  Rebuilds the tops scene graph (the graph under the topsList node)
*/
void
SmWellLogKitP::buildTopsSceneGraph(void)
{
  SoSeparator *topsList =
    (SoSeparator *)PUBLIC(this)->getAnyPart("topsList", TRUE);
  topsList->removeAllChildren();

  const SbString *strings = PUBLIC(this)->topsNames.getValues(0);
  for (int i=0;i<PUBLIC(this)->topsNames.getNum();i++) {
    SoSeparator *top = new SoSeparator;
    SoTranslation *toppos = new SoTranslation;
    SoSphere *sphere = new SoSphere;
    SoTranslation *textpos = new SoTranslation;
    SoVRMLBillboard *billboard = new SoVRMLBillboard;
    SoText3 *text = new SoText3;

    float depth;
    if (PUBLIC(this)->topsDepths.getNum() <= i)
      depth = -PUBLIC(this)->topsDepths[PUBLIC(this)->topsDepths.getNum()-1];
    else
      depth = -PUBLIC(this)->topsDepths[i];

    const SbVec3d *wcoords = PUBLIC(this)->wellCoord.getValues(0);
    int numdepths = PUBLIC(this)->wellCoord.getNum();
    int j;
    for (j=0;j<numdepths;j++) {
      if (wcoords[j][2] <= depth) {
        j++;
        break;
      }
    }
    if (j==0) j = 1;
    UTMPosition *utm = (UTMPosition *)PUBLIC(this)->getAnyPart("utm", TRUE);
    toppos->translation.setValue((float) (wcoords[j-1][0]-utm->utmposition.getValue()[0]),
                                 (float) (wcoords[j-1][1]-utm->utmposition.getValue()[1]),
                                 depth);

    sphere->radius.connectFrom(&this->radiusEngine->oa);

    textpos->translation.connectFrom(&this->radiusEngine->oA);

    text->string.setValue(strings[i]);

    top->addChild(toppos);
    top->addChild(sphere);
    top->addChild(billboard);
    billboard->addChild(textpos);
    billboard->addChild(text);
    topsList->addChild(top);
  }
}

static void
interpolate(sm_well_pos & p, const sm_well_pos & prev, const sm_well_pos & next,
            double newdepth)
{
  double delta = next.tvdepth - prev.tvdepth;
  if (delta == 0.0) {
    p = prev;
    return;
  }
  double t = (newdepth - prev.tvdepth) / delta;

  if (t < 0.0 || t > 1.0) {
    //    myfprintf(stderr,"newdepth: %g\n", newdepth);
  }
  //  assert(t >= 0.0f && t <= 1.0);

  float ft = (float) t;

  SbVec3f vec = next.pos - prev.pos;
  p.pos = prev.pos + vec * ft;
  p.left = prev.left; // FIXME: interpolate?
  p.right = prev.right;
  p.mdepth = prev.mdepth + (next.mdepth-prev.mdepth) * t;
  p.tvdepth = newdepth;
  p.realidx = next.realidx;
  p.col = next.col;
}

// time/depth interpolation function. Used when converting between
// time and detph
static float
time_depth_interpolate(double val, const SbList <double> & data)
{
  int i = 0 , n = data.getLength() / 2;

  while (i < n && val > data[i*2+1]) i++;

  int i0 = i;
  int i1 = i + 1;

  if (i1 >= n) {
    i0 = n-2;
    i1 = n-1;
  }

  double from[2];
  double to[2];

  from[0] = data[i0*2+1];
  from[1] = data[i1*2+1];

  to[0] = data[i0*2];
  to[1] = data[i1*2];

  double fd = from[1] - from[0];
  double td = to[1] - to[0];

  if (fd <= 0.0 || td <= 0.0) {
//     myfprintf(stderr,"error (%d %d, %d: %g %g %g %g\n",
//             i0, i1, i,
//            from[0], from[1], to[0], to[1]);
  }

  //assert(fd > 0.0 && td > 0.0);

  double t = (val - from[0]) / fd;

  //  fprintf(stderr,"convert: %g %g\n", val, (float) (to[0] + t * td));

  return (float) (to[0] + t * td);
}

// convert between time and depth
void
SmWellLogKitP::convertDepth(const SbList <double> & data)
{
  int i, n = this->poslist.getLength();
  if (n < 2) return;

  for (i = 0; i < n; i++) {
    sm_well_pos & pos = this->poslist[i];
    pos.pos[2] = - time_depth_interpolate((double) -pos.pos[2], data);
  }
}

// called when something has changed and the internal list needs to be
// regenerated.
void
SmWellLogKitP::oneshot_cb(void * closure, SoSensor * s)
{
  SmWellLogKitP * thisp = (SmWellLogKitP*) closure;
  thisp->processingoneshot = TRUE;

  thisp->prevaxis = SbVec3f(0.0f, 0.0f, 0.0f);
  thisp->updateList();
  thisp->buildGeometry();
  thisp->buildTopsSceneGraph();
  thisp->updateName();
  thisp->generateFaces(SbVec3f(1.0f, 0.0f, 0.0f));
  if (thisp->oneshot->isScheduled()) thisp->oneshot->unschedule();
  thisp->processingoneshot = FALSE;;
}

// need to be called when something changes in the input data. Will
// generate a new list of well_pos structures.
void
SmWellLogKitP::updateList(void)
{
  this->poslist.truncate(0);
  int n = PUBLIC(this)->wellCoord.getNum();
  SbBool colorpersegment = PUBLIC(this)->wellColor.getNum() == n;

  if (n == 0) {
    SoIndexedFaceSet * fs = (SoIndexedFaceSet*) PUBLIC(this)->getPart("faceSet", TRUE);
    fs->coordIndex.setNum(0);

    SoLODExtrusion * lod = (SoLODExtrusion*) PUBLIC(this)->getAnyPart("well", TRUE);
    lod->spine.setNum(0);
    return;
  }

  UTMPosition * utm = (UTMPosition*) PUBLIC(this)->getAnyPart("utm", TRUE);
  const SbVec3d * welldata = PUBLIC(this)->wellCoord.getValues(0);

  SbVec3d origin = SbVec3d(welldata[0][0], welldata[0][1], 0.0);

  // set origin to avoid floating point precision issues
  utm->utmposition = origin;

  sm_well_pos pos;
  int cnt = 0;
  double undefval = PUBLIC(this)->undefVal.getValue();

  double prevdepth = 0.0;
  SbVec3f prev(0.0f, 0.0f, 0.0f);
  const SbColor * colptr = PUBLIC(this)->wellColor.getValues(0);

  for (int i = 0; i < n; i++) {
    SbVec3d t = SbVec3d(welldata[i][0],
                        welldata[i][1],
                        welldata[i][2]);
    if (t[0] == undefval || t[1] == undefval) continue;
    pos.tvdepth = -t[2];
    t -= origin;

    pos.pos = SbVec3f((float) t[0], (float) t[1], (float) t[2]);
    pos.col = SbColor(0.8f, 0.8f, 0.8f);
    if (colorpersegment) {
      pos.col = colptr[i];
    }
    else {
      pos.col = colptr ? colptr[0] : SbColor(0.7f, 0.7f, 0.7f);
    }
    pos.mdepth = PUBLIC(this)->getDepth(i);
    pos.left = PUBLIC(this)->getLeftCurveData(i);
    pos.right = PUBLIC(this)->getRightCurveData(i);
    pos.realidx = i;

    // workaround for some LAS files that specifies an undef value,
    // but use some other value instead
    if (SbAbs(pos.left-undefval) < 1.0f) pos.left = undefval;
    if (SbAbs(pos.right-undefval) < 1.0f) pos.right= undefval;

    if (!this->poslist.getLength() || SbAbs(pos.mdepth-prevdepth) >= 0.0) {
      this->poslist.append(pos);
      prevdepth = pos.mdepth;
    }
  }
}

#undef PUBLIC


text:
.landing .navigation {
    width: 100%;
    background-color: #fff;
    height: 78px;
    text-align: center;
}

.landing .navigation .logo-area {
    display: inline-block;
    width:200px;
    height:78px;
    float: left;
}

.landing .navigation .logo-area .logo-img {
    width: 130px;
    height: 22px;
    margin-top: 30px;
    margin-left: 32px;
    cursor: pointer;
}

.landing .navigation .navigation-area {
    height: 78px;
    margin: 0 auto;
    display: inline-block;
    vertical-align: top;
    text-align: left;
}

.landing .navigation .navigation-button-box {
    display: inline-block;
    padding-top: 35px;
    height: 20px;
    width: 84px;
}

.landing .navigation .navigation-button-box button {
    opacity: 0.87;
    background: transparent;
    border: 0;
    cursor: pointer;
    font-size: 12px;
}

.landing .navigation .navigation-button-box button.signup {
    color: #ef5350;
    width:85px;
}
.landing .navigation .main-search-area{
    width:440px;

    margin: 0 auto;
    padding-top:35px;
    padding-left:70px;
    background: none;
    height:35px;
    margin:0 auto;
    display:inline-block;
}
.landing .navigation .main-search-area i{
    font-size:15px;
    display: inline-block;
    margin:0 auto;
}
.landing .navigation .main-search-area input{
    width:350px;
    display: inline-block;
    border:none;
    border-bottom:1px solid black;
}
input[class="main-search"]::-webkit-input-placeholder{
    font-size:12px;
    opacity:0.5;
}
.landing .navigation .signin-area {
    float: right;
    height: 50px;
    vertical-align: top;
    display: inline-block;
    width: 120px;
    padding-top: 35px;
    padding-right: 35px;
    text-align: right;
    margin: 0 auto;
}

.landing .navigation .signin-area button {
    font-size: 12px;
    color: #ef5350;
    background: transparent;
    border: 0;
    cursor: pointer;
}

.landing .main {
    height:300px;
    background-color: #F4f5f5;
    background: url("../img/landing_main.png");
    background-size: 100% 100%;
}

.landing .main .center-container {

    margin: 0 auto;
    width:350px;
    font-size: 0;
    background-color: transparent;
    margin-left: 41.7%;
        padding-top: 100px;
}

.landing .main .center-container h2 {
    margin:0 auto;
    color: #EF5350;
    margin-bottom: 15px;
    font-size: 27px;
}

.landing .main .center-container h3 {
    margin:0 auto;
    color: #ffffff;
    font-size: 21px;
}

.landing .main .center-container .main-button-area {
    width: 70px;
    display: inline-block;
    height: 47px;
}

.landing .main .center-container .main-button {
    width: 47px;
    height: 47px;
    border: 0px;
}

.landing .main .center-container .main-button.camera {
    background: url("../img/camera-gray.png");
    background-size: 47px 47px;
}

.landing .main .center-container .main-button.camera:hover {
    background: url("../img/camera-red.png");
    background-size: 47px 47px;
}

.landing .main .center-container .main-button.gallery {
    background: url("../img/gallery-gray.png");
    background-size: 47px 47px;
}

.landing .main .center-container .main-button.gallery:hover {
    background: url("../img/gallery-red.png");
    background-size: 47px 47px;
}

.landing .main .center-container .main-button.folder {
    background: url("../img/folder-gray.png");
    background-size: 47px 47px;
}

.landing .main .center-container .main-button.folder:hover {
    background: url("../img/folder-red.png");
    background-size: 47px 47px;
}

.landing .after-login-area {
    width: 100%;
    color: red;
    text-align: center;
    background-color: #EF5350;
    height: 45px;
    margin:0 auto;
}

.landing .after-login-area .cash-status {
    height: 45px;
    width: 32%;
    display: inline-block;
    cursor: pointer;
    border-right: 1px solid rgba(255, 255, 255, 0.3);

}

.landing .after-login-area .cash-status .fixed {
    font-size: 15px;
    opacity: 0.87;
    color: white;
    width: 60%;
    display: inline-block;
    padding-top: 10px;
}

.landing .after-login-area .cash-status .changeable {
    font-size: 15px;
    opacity: 0.87;
    font-weight: bold;
    color: white;
    width: 30%;
    display: inline-block;
    padding-top: 10px;
}

.landing .after-login-area .cash-charge {
    margin: 0 auto;
    width: 32%;
    font-size: 15px;
    opacity: 0.87;
    color: white;
    display: inline-block;
    cursor: pointer;
    border-right: 1px solid rgba(255, 255, 255, 0.3);
    padding-top: 10px;
    height: 45px;
}

.landing .after-login-area .bought-notes {
    height: 45px;
    width: 32%;
    font-size: 15px;
    opacity: 0.87;
    color: white;
    display: inline-block;
    cursor: pointer;
    padding-top: 10px;
}

.landing .search {
    font-size: 0;
    width: 100%;
    margin: 0 auto;
}

.landing .search .search-area {
    width: 50%;
    display: inline-block;
    height: 336px;
    vertical-align: top;
}
.landing .search .class{
    background-color:#EEEEEE;
    margin: 0 auto;
}
.landing .search .class button{
    border:none;
    margin:0 auto;
    width:100%;
    height:100%;
    background: inherit;
}
.landing .search .class h4 {
    font-size: 18px;
    margin:0 auto;
    color: #EF5350;
   margin-left:62px;
    text-align: left;
    vertical-align: top;
}
.landing .search .class h5 {
 font-size:12px;
    color:#000000;
    text-align: left;
    margin-left: 62px;
    margin-top: 15px;
    opacity: 0.38;
    margin-bottom:220px;
}
.landing .search .class .b{
    background: url("../img/table_temp.png");
    background-size:100% 100%;
}

.landing .search .search-area.school {
    background-color: #e0e0df;
    margin: 0 auto;
}

.landing .search .search-area.school .search-form {
    margin-top: 32px;
    margin-left: 31px;
}

.landing .search .search-area.school .search-form input[type="text"] {
    font-size: 14px;
    opacity: 0.38;
    width: 87%;
    height: 40px;
    background-color: white;
}
.landing .search .search-area.school .search-form .input-group-addon{
    font-size: 16px;
}

.landing .search .search-area.school h4 {
    font-size: 14px;
    opacity: 0.38;
    text-align: left;
    color:#000000;
    margin-left:31px;
    margin-top:16px;
}

.landing .search .search-area.school .texts {
    font-size: 14px;
    opacity: 0.38;
    margin-top: 12px;
    margin-left: 31px;
}
.landing .search .search-area.school .form{
    text-align: center;
    background: white;
    margin:0 auto;
    margin-top:20px;
    margin-left:31px;
    width:87%;
    height:140px;
}
.landing .search .school .contents{
    margin-top:10px;
    margin-left:10px;
}
.landing .search .school .contents tr th{
    font-size:14px;
    opacity: 0.5;
    width:70px;
    text-align: center;
}

.landing .register-area {
    background-color: #EF5350;
    height: 325px;
    width: 100%;
    margin:0 auto;
}
.landing .register-area .texts{
    color:#FFFFFF;
    font-size:17px;
    width:100%;
    padding-top:39px;
    text-align: center;
}
.landing .register-area .register{
    margin-top:50px;
}
.landing .register-area input{
    font-size:17px;
    border: none;
    background: inherit;
}
input[class="name"]::-webkit-input-placeholder{
    color:white !important;
}
input[class="e-mail"]::-webkit-input-placeholder{
    color:white !important;
}
input[class="pw"]::-webkit-input-placeholder{
    color:white !important;
    opacity: 0.38;
}
input[class="pw-confirm"]::-webkit-input-placeholder{
    color:white !important;
    opacity: 0.38;
}
.landing .register-area .name-name{
    display: inline-block;
    margin-left:7%;
    width:34%;
}
.landing .register-area .pw-pw{
    display: inline-block;
    width:34%;
    margin-left:17%;
    margin-right:7%;
}
.landing .register-area .e-mail-e-mail{
    display: inline-block;
    margin-left:7%;
    width:34%;
}
.landing .register-area .pw-confirm-pw-confirm{
    display: inline-block;
    width:34%;
    margin-left:17%;
    margin-right:7%;
}
.landing .register-area .name-border{
    width:34%;
    margin-left:7%;
    display: inline-block;
    margin-top:5px;
    background-color: white;
    height:1px;
    margin-bottom: 56px;
}
.landing .register-area .pw-border{
    width:34%;
    margin-left:17%;
    margin-right: 7%;
    display: inline-block;
    margin-top:5px;
    background-color: white;
    height:1px;
    margin-bottom: 56px;
}
.landing .register-area .e-mail-border{
    width:34%;
    margin-left:7%;
    display: inline-block;

    background-color: white;
    height:1px;
}
.landing .register-area .pw-confirm-border{
    width:34%;
    margin-left:17%;
    margin-right: 7%;
    display: inline-block;

    background-color: white;
    height:1px;
}
.landing .register-area button{
    border:none;
    font-size:17px;
    color:white;
    background: inherit;
    margin-top:39px;
    margin-left:85%;
}

redpajama_set_name: RedPajamaGithub


text:
package com.java110.po.userAttr;

import java.io.Serializable;

/**
 * 类表述: Po 数据模型实体对象 基本保持与数据库模型一直 用于 增加修改删除 等时的数据载体
 * add by 吴学文 at 2021-11-26 13:28:38 mail: 928255095@qq.com
 * open source address: https://gitee.com/wuxw7/MicroCommunity
 * 官网:http://www.homecommunity.cn
 * 温馨提示:如果您对此文件进行修改 请不要删除原有作者及注释信息,请补充您的 修改的原因以及联系邮箱如下
 * // modify by 张三 at 2021-09-12 第10行在某种场景下存在某种bug 需要修复,注释10至20行 加入 20行至30行
 */
public class UserAttrPo implements Serializable {

    private String attrId;
    private String specCd;
    private String statusCd = "0";
    private String id;
    private String userId;
    private String value;

    public String getAttrId() {
        return attrId;
    }

    public void setAttrId(String attrId) {
        this.attrId = attrId;
    }

    public String getSpecCd() {
        return specCd;
    }

    public void setSpecCd(String specCd) {
        this.specCd = specCd;
    }

    public String getStatusCd() {
        return statusCd;
    }

    public void setStatusCd(String statusCd) {
        this.statusCd = statusCd;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}


text:
<?php

namespace AppBundle\Controller;

use AppBundle\Entity\User;
use AppBundle\Entity\UserSkill;
use AppBundle\Form\UserEditSkillType;
use AppBundle\Form\UserType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class UserController extends Controller {

	public function indexAction() {
		$em = $this->getDoctrine()->getManager();
		$repo = $em->getRepository('AppBundle:User');
		$repoSkill = $em->getRepository('AppBundle:Skill');
		$users = $repo->findUsersEager();
		$skills = $repoSkill->findAll();

		return $this->render('AppBundle:User:list.html.twig', array(
					'users' => $users,
					'skills' => $skills
		));
	}

	public function profileAction($id) {
		$em = $this->getDoctrine()->getManager();
		$repoUser = $em->getRepository('AppBundle:User');
		$repoSkill = $em->getRepository('AppBundle:Skill');
		$repoProjet = $em->getRepository('AppBundle:Project');
		$repoNotif = $em->getRepository('AppBundle:Notification');

		$skills = $repoSkill->getSkillsWithChilds();
		$user = $repoUser->findOneUserEager($id);
		$projects = $repoProjet->findProjectUserEager($id);
		$notifications = $repoNotif->findUserNotifications($id);
		$inviteList = $repoProjet->findProjectsUserIsNotIn($id);

		return $this->render('AppBundle:User:profil.html.twig', array(
					'user' => $user,
					'skills' => $skills,
					'projects' => $projects,
					'notifications' => $notifications,
					'inviteList' => $inviteList
		));
	}

	public function updateProfilAction(User $user, Request $req) {
		$form = $this->createForm(new UserType(), $user, array(
			'action' => $this->generateUrl('user_update', array('id' => $user->getId()))
		));

		$form->handleRequest($req); //permet d'ajouter les valeurs

		if ($form->isValid()) {
			$em = $this->getDoctrine()->getManager();
			$em->flush();
			return $this->redirect($this->generateUrl('user_profile', array('id' => $user->getId())));
		}

		return $this->render('AppBundle:User:update.html.twig', array(
					'userform' => $form->createView(),
					'user' => $user,
		));
	}

	public function updateSkillProfilAction(User $user, Request $req) {
		$form = $this->createForm(new UserEditSkillType(), $user, array(
			'action' => $this->generateUrl('user_updateskill', array('id' => $user->getId()))
		));
		$form->handleRequest($req); //permet d'ajouter les valeurs

		if ($form->isValid()) {
			$em = $this->getDoctrine()->getManager();
			$em->flush();
			return $this->redirect($this->generateUrl('user_profile', array('id' => $user->getId())));
		}

		return $this->render('AppBundle:User:updateSkillProfil.html.twig', array(
					'userSkillForm' => $form->createView(),
					'user' => $user,
		));
	}

	public function addSkillUserAction(Request $req) {
		$em = $this->getDoctrine()->getManager();
		$repoUser = $em->getRepository('AppBundle:User');
		$user = $repoUser->find($req->request->get('userId'));

		$repoSkill = $em->getRepository('AppBundle:Skill');
		$skill = $repoSkill->find($req->request->get('skillId'));

		$repoUserSkill = $em->getRepository('AppBundle:UserSkill');
		$userSkill = $repoUserSkill->find($req->request->get('userSkillId'));

		$value = $req->request->get('skillValue');

		if ($value > 0) {
			if ($skill->existInUser($user)) {
				$userSkill->setValue($value);
				$response = new Response(json_encode(array(
							'status' => 'update',
				)));
			} else {
				if ($skill->getParent()->existInUser($user)) {

					$newSkill = new UserSkill();
					$newSkill->setUser($user)->setSkill($skill)->setValue($value);
					$response = new Response(json_encode(array(
								'status' => 'add',
					)));
					$em->persist($newSkill);
				} else {

					$newParentSkill = new UserSkill();
					$newParentSkill->setUser($user)->setSkill($skill->getParent())->setValue(-1);

					$newSkill = new UserSkill();
					$newSkill->setUser($user)->setSkill($skill)->setValue($value);
					$response = new Response(json_encode(array(
								'status' => 'add & parents',
					)));

					$em->persist($newSkill);
					$em->persist($newParentSkill);
				}
			}
		} else {
			$cpt = 0;
			foreach ($skill->getParent()->getChilds() as $child) {
				if ($child->existInUser($user)) {
					$cpt ++;
				}
			}

			if ($cpt >= 2) {
				$em->remove($userSkill);

				$response = new Response(json_encode(array(
							'status' => $userSkill->getUser()->getFirstname(),
				)));
			} else {
				$skillId = $skill->getParent()->getId();
				$userId = $req->request->get('userId');

				$repoUserParentSkill = $em->getRepository('AppBundle:UserSkill');
				$userParentSkill = $repoUserParentSkill->getUserSkillBySkillAndUser($skillId, $userId);

				$em->remove($userSkill);
				$em->remove($userParentSkill);

				$response = new Response(json_encode(array(
							'status' => $userParentSkill->getId(),
				)));
			}
		}
		$em->flush();
		$response->headers->set('Content-Type', 'application/json');
		return $response;
	}

	public function notifAction(Request $req) {
		$em = $this->getDoctrine()->getManager();
		$repoN = $em->getRepository('AppBundle:Notification');
		$notif = $repoN->find($req->request->get('notifId'));

		if ($req->request->get('type') === 'read') {
			$notif->setStatus(false);
		} elseif ($req->request->get('type') === 'delete') {
			$em->remove($notif);
		}
		$em->flush();

		$response = new Response(json_encode(array(
					'status' => 'OK',
					'id' => $req->request->get('notifId')
		)));
		$response->headers->set('Content-Type', 'application/json');
		return $response;
	}
}


text:
// Template Source: BaseEntityRequest.java.tt
// ------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All Rights Reserved.  Licensed under the MIT License.  See License in the project root for license information.
// ------------------------------------------------------------------------------

package com.microsoft.graph.requests;

import com.microsoft.graph.http.IRequestBuilder;
import com.microsoft.graph.core.ClientException;
import com.microsoft.graph.models.IdentityProvider;
import java.util.Arrays;
import java.util.EnumSet;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.microsoft.graph.core.IBaseClient;
import com.microsoft.graph.http.BaseRequest;
import com.microsoft.graph.http.HttpMethod;

// **NOTE** This file was generated by a tool and any changes will be overwritten.

/**
 * The class for the Identity Provider Request.
 * @deprecated The identityProvider API is deprecated and will stop returning data on March 2023. Please use the new identityProviderBase API.
 */
@Deprecated
public class IdentityProviderRequest extends BaseRequest<IdentityProvider> {

    /**
     * The request for the IdentityProvider
     *
     * @param requestUrl     the request URL
     * @param client         the service client
     * @param requestOptions the options for this request
     */
    public IdentityProviderRequest(@Nonnull final String requestUrl, @Nonnull final IBaseClient<?> client, @Nullable final java.util.List<? extends com.microsoft.graph.options.Option> requestOptions) {
        super(requestUrl, client, requestOptions, IdentityProvider.class);
    }

    /**
     * Gets the IdentityProvider from the service
     *
     * @return a future with the result
     */
    @Nonnull
    public java.util.concurrent.CompletableFuture<IdentityProvider> getAsync() {
        return sendAsync(HttpMethod.GET, null);
    }

    /**
     * Gets the IdentityProvider from the service
     *
     * @return the IdentityProvider from the request
     * @throws ClientException this exception occurs if the request was unable to complete for any reason
     */
    @Nullable
    public IdentityProvider get() throws ClientException {
       return send(HttpMethod.GET, null);
    }

    /**
     * Delete this item from the service
     *
     * @return a future with the deletion result
     */
    @Nonnull
    public java.util.concurrent.CompletableFuture<IdentityProvider> deleteAsync() {
        return sendAsync(HttpMethod.DELETE, null);
    }

    /**
     * Delete this item from the service
     * @return the resulting response if the service returns anything on deletion
     *
     * @throws ClientException if there was an exception during the delete operation
     */
    @Nullable
    public IdentityProvider delete() throws ClientException {
        return send(HttpMethod.DELETE, null);
    }

    /**
     * Patches this IdentityProvider with a source
     *
     * @param sourceIdentityProvider the source object with updates
     * @return a future with the result
     */
    @Nonnull
    public java.util.concurrent.CompletableFuture<IdentityProvider> patchAsync(@Nonnull final IdentityProvider sourceIdentityProvider) {
        return sendAsync(HttpMethod.PATCH, sourceIdentityProvider);
    }

    /**
     * Patches this IdentityProvider with a source
     *
     * @param sourceIdentityProvider the source object with updates
     * @return the updated IdentityProvider
     * @throws ClientException this exception occurs if the request was unable to complete for any reason
     */
    @Nullable
    public IdentityProvider patch(@Nonnull final IdentityProvider sourceIdentityProvider) throws ClientException {
        return send(HttpMethod.PATCH, sourceIdentityProvider);
    }

    /**
     * Creates a IdentityProvider with a new object
     *
     * @param newIdentityProvider the new object to create
     * @return a future with the result
     */
    @Nonnull
    public java.util.concurrent.CompletableFuture<IdentityProvider> postAsync(@Nonnull final IdentityProvider newIdentityProvider) {
        return sendAsync(HttpMethod.POST, newIdentityProvider);
    }

    /**
     * Creates a IdentityProvider with a new object
     *
     * @param newIdentityProvider the new object to create
     * @return the created IdentityProvider
     * @throws ClientException this exception occurs if the request was unable to complete for any reason
     */
    @Nullable
    public IdentityProvider post(@Nonnull final IdentityProvider newIdentityProvider) throws ClientException {
        return send(HttpMethod.POST, newIdentityProvider);
    }

    /**
     * Creates a IdentityProvider with a new object
     *
     * @param newIdentityProvider the object to create/update
     * @return a future with the result
     */
    @Nonnull
    public java.util.concurrent.CompletableFuture<IdentityProvider> putAsync(@Nonnull final IdentityProvider newIdentityProvider) {
        return sendAsync(HttpMethod.PUT, newIdentityProvider);
    }

    /**
     * Creates a IdentityProvider with a new object
     *
     * @param newIdentityProvider the object to create/update
     * @return the created IdentityProvider
     * @throws ClientException this exception occurs if the request was unable to complete for any reason
     */
    @Nullable
    public IdentityProvider put(@Nonnull final IdentityProvider newIdentityProvider) throws ClientException {
        return send(HttpMethod.PUT, newIdentityProvider);
    }

    /**
     * Sets the select clause for the request
     *
     * @param value the select clause
     * @return the updated request
     */
     @Nonnull
     public IdentityProviderRequest select(@Nonnull final String value) {
         addSelectOption(value);
         return this;
     }

    /**
     * Sets the expand clause for the request
     *
     * @param value the expand clause
     * @return the updated request
     */
     @Nonnull
     public IdentityProviderRequest expand(@Nonnull final String value) {
         addExpandOption(value);
         return this;
     }

}


text:
from contextlib import contextmanager
from socket import timeout as SocketTimeout

import etcd3gw as etcd
from oslo_log import log
import six
import urllib3
from urllib3 import connection
from urllib3 import exceptions

from dragonflow.common import exceptions as df_exceptions
from dragonflow.db import db_api
from dragonflow.db import db_common

LOG = log.getLogger(__name__)

# Monkey patch urllib3 to close connections that time out.  Otherwise,
# etcd will leak socket handles when we time out watches.

ETCD_READ_TIMEOUT = 20

@contextmanager
def _error_catcher(self):
    """
    Catch low-level python exceptions, instead re-raising urllib3
    variants, so that low-level exceptions are not leaked in the
    high-level api.
    On exit, release the connection back to the pool.
    """
    try:
        try:
            yield

        except SocketTimeout:
            # FIXME: Ideally we'd like to include the url in the
            # ReadTimeoutError but there is yet no clean way to
            # get at it from this context.
            raise exceptions.ReadTimeoutError(
                self._pool, None, 'Read timed out.')

        except connection.BaseSSLError as e:
            # FIXME: Is there a better way to differentiate between SSLErrors?
            if 'read operation timed out' not in str(e):  # Defensive:
                # This shouldn't happen but just in case we're missing an edge
                # case, let's avoid swallowing SSL errors.
                raise

            raise exceptions.ReadTimeoutError(
                self._pool, None, 'Read timed out.')

        except connection.HTTPException as e:
            # This includes IncompleteRead.
            raise exceptions.ProtocolError('Connection broken: %r' % e, e)
    except Exception:
        # The response may not be closed but we're not going to use it anymore
        # so close it now to ensure that the connection is released back to the
        #  pool.
        if self._original_response and not self._original_response.isclosed():
            self._original_response.close()

        # Before returning the socket, close it.  From the server's
        # point of view,
        # this socket is in the middle of handling an SSL handshake/HTTP
        # request so it we were to try and re-use the connection later,
        #  we'd see undefined behaviour.
        #
        # Still return the connection to the pool (it will be
        # re-established next time it is used).
        self._connection.close()

        raise
    finally:
        if self._original_response and self._original_response.isclosed():
            self.release_conn()
urllib3.HTTPResponse._error_catcher = _error_catcher

class EtcdDbDriver(db_api.DbApi):

    def __init__(self):
        super(EtcdDbDriver, self).__init__()
        self.client = None
        self.current_key = 0
        self.notify_callback = None

    def initialize(self, db_ip, db_port, **args):
        self.client = etcd.client(host=db_ip, port=db_port)

    def create_table(self, table):
        # Not needed in etcd
        pass

    def delete_table(self, table):
        self.client.delete_prefix(self._make_key(table))

    @staticmethod
    def _make_key(table, obj_id=None):
        if obj_id:
            key = '/{}/{}'.format(table, obj_id)
        else:
            key = '/{}/'.format(table)
        return key

    def get_key(self, table, key, topic=None):
        key = self._get_key(self._make_key(table, key), key)
        if not six.PY2:
            key = key.decode("utf-8")
        return key

    def _get_key(self, table_key, key):
        value = self.client.get(table_key)
        if len(value) > 0:
            return value.pop()
        raise df_exceptions.DBKeyNotFound(key=key)

    def set_key(self, table, key, value, topic=None):
        self.client.put(self._make_key(table, key), value)

    def create_key(self, table, key, value, topic=None):
        self.client.put(self._make_key(table, key), value)

    def delete_key(self, table, key, topic=None):
        deleted = self.client.delete(self._make_key(table, key))
        if not deleted:
            raise df_exceptions.DBKeyNotFound(key=key)

    def get_all_entries(self, table, topic=None):
        res = []
        directory = self.client.get_prefix(self._make_key(table))
        for entry in directory:
            value = entry[0]
            if value:
                if not six.PY2:
                    value = value.decode("utf-8")
                res.append(value)
        return res

    def get_all_keys(self, table, topic=None):
        res = []
        directory = self.client.get_prefix(self._make_key(table))
        table_name_size = len(table) + 2
        for entry in directory:
            _key = entry[1]["key"]
            key = _key[table_name_size:]
            if not six.PY2:
                key = key.decode("utf-8")
            res.append(key)
        return res

    def _allocate_unique_key(self, table):
        table_key = self._make_key(db_common.UNIQUE_KEY_TABLE, table)
        prev_value = 0
        try:
            prev_value = int(self._get_key(table_key, table))
        except df_exceptions.DBKeyNotFound:
            if prev_value == 0:
                # Create new key
                if self.client.create(table_key, "1"):
                    return 1
            raise RuntimeError()  # Error occurred. Restart the allocation

        new_unique = prev_value + 1
        if self.client.replace(table_key, str(prev_value), str(new_unique)):
            return new_unique
        raise RuntimeError()  # Error occurred. Restart the allocation

    def allocate_unique_key(self, table):
        while True:
            try:
                return self._allocate_unique_key(table)
            except RuntimeError:
                pass

    def process_ha(self):
        # Not needed in etcd
        pass


text:
import feedparser
import re

# Takes a filename of URL of a blog feed and classifies the entries
def read(feed,classifier):
  # Get feed entries and loop over them
  f=feedparser.parse(feed)
  for entry in f['entries']:
    print
    print '-----'
    # Print the contents of the entry
    print 'Title:     '+entry['title'].encode('utf-8')
    print 'Publisher: '+entry['publisher'].encode('utf-8')
    print
    print entry['summary'].encode('utf-8')

    # Combine all the text to create one item for the classifier
    fulltext='%s\n%s\n%s' % (entry['title'],entry['publisher'],entry['summary'])

    # Print the best guess at the current category
    print 'Guess: '+str(classifier.classify(entry))

    # Ask the user to specify the correct category and train on that
    cl=raw_input('Enter category: ')
    classifier.train(entry,cl)

def entryfeatures(entry):
  splitter=re.compile('\\W*')
  f={}

  # Extract the title words and annotate
  titlewords=[s.lower() for s in splitter.split(entry['title'])
          if len(s)>2 and len(s)<20]
  for w in titlewords: f['Title:'+w]=1

  # Extract the summary words
  summarywords=[s.lower() for s in splitter.split(entry['summary'])
          if len(s)>2 and len(s)<20]

  # Count uppercase words
  uc=0
  for i in range(len(summarywords)):
    w=summarywords[i]
    f[w]=1
    if w.isupper(): uc+=1

    # Get word pairs in summary as features
    if i<len(summarywords)-1:
      twowords=' '.join(summarywords[i:i+1])
      f[twowords]=1

  # Keep creator and publisher whole
  f['Publisher:'+entry['publisher']]=1

  # UPPERCASE is a virtual word flagging too much shouting
  if float(uc)/len(summarywords)>0.3: f['UPPERCASE']=1

  return f


text:
pop-data
========

END OF LIFE
-----------
The `pop-data` component v2.1.0 is now end-of-life. The CSV sub-component has
been forked and pushed into its own repository:

* popphp/pop-csv

[![Build Status](https://travis-ci.org/popphp/pop-data.svg?branch=master)](https://travis-ci.org/popphp/pop-data)
[![Coverage Status](http://cc.popphp.org/coverage.php?comp=pop-data)](http://cc.popphp.org/pop-data/)

OVERVIEW
--------
`pop-data` provides a streamlined way to convert common data types. With it, you can easily give it
some native PHP data and quickly produce a serialized version of that data in a common data type,
such as CSV, JSON, SQL, XML or YAML. Or, conversely, you can give it some serialized data, an it
will auto-detect the format and convert it to native PHP data.

`pop-data`is a component of the [Pop PHP Framework](http://www.popphp.org/).

INSTALL
-------

Install `pop-data` using Composer.

    composer require popphp/pop-data

BASIC USAGE
-----------

### Serialize Data

```php
$phpData = [
    [
        'first_name' => 'Bob',
        'last_name'  => 'Smith'
    ],
    [
        'first_name' => 'Jane',
        'last_name'  => 'Smith'
    ]
];

$data = new Pop\Data\Data($phpData);

$csvString   = $data->serialize('csv');
$jsonString  = $data->serialize('json');
$sqlString   = $data->serialize('sql');
$xmlString   = $data->serialize('xml');
$yamlString  = $data->serialize('yaml');
```

The $csvString variable now contains:

    first_name,last_name
    Bob,Smith
    Jane,Smith

The $jsonString variable now contains:

    [
        {
            "first_name": "Bob",
            "last_name": "Smith"
        },
        {
            "first_name": "Jane",
            "last_name": "Smith"
        }
    ]

The $sqlString variable now contains:

    INSERT INTO data (first_name, last_name) VALUES
    ('Bob', 'Smith'),
    ('Jane', 'Smith');

The $xmlString variable now contains:

    <?xml version="1.0" encoding="utf-8"?>
    <data>
      <row>
        <first_name>Bob</first_name>
        <last_name>Smith</last_name>
      </row>
      <row>
        <first_name>Jane</first_name>
        <last_name>Smith</last_name>
      </row>
    </data>

The $yamlString variable now contains:

    ---
    - first_name: Bob
      last_name: Smith
    - first_name: Jane
      last_name: Smith
    ...

### Unserialize Data

You can either pass the data object a direct string of serialized data or a file containing a string of
serialized data. It will detect which one it is and parse it accordingly.

##### String

```php
$csv     = new Pop\Data\Data($csvString);
$phpData = $csv->unserialize();
```

##### File

```php
$xml     = new Pop\Data\Data('/path/to/file.xml');
$phpData = $xml->unserialize();
```

### Convert Between Data Types

```php
$csv = new Pop\Data\Data($csvString);
$xml = $csv->convert('xml');
```

### Write to File

```php
$phpData = [ ... ];

$data = new Pop\Data\Data($phpData);
$data->serialize('csv');
$data->writeToFile('/path/to/file.csv');
```

### Output to HTTP

```php
$phpData = [ ... ];

$data = new Pop\Data\Data($phpData);
$data->serialize('csv');
$data->outputToHttp();
```

##### Force download of file

```php
$phpData = [ ... ];

$data = new Pop\Data\Data($phpData);
$data->serialize('csv');
$data->outputToHttp('my-file.csv', true);
```


text:
@import url(http://fonts.googleapis.com/css?family=Lato:300,400,700,900,300italic,400italic,700italic,900italic);
/* SKIN SELECT */
#skin-select h3, #skin-select h4 { font-family: 'Lato', sans-serif; }
#skin-select { position:fixed; top:60px; width:290px; z-index:9000; background:#fff;
  -webkit-box-shadow: 0px 2px 2px 0px #050505;
          box-shadow: 2px 2px 2px 0px rgba(0,0,0,.1);
}
#skin-select #toggle { position:absolute; top:0; right:-40px; display:block; width:40px; height:40px; cursor:pointer; background: #222 url(img/style-toggle.png) 0 0 no-repeat; }
#skin-select #toggle.active { background-position:0 -40px; }
#skin-select ul { margin:0; padding:0; list-style:none; }
#skin-select ul li { display:inline-block; margin-right:1px; margin-bottom:4px; }
#skin-select ul li a { padding: 4px 6px; font-family:Tahoma, "Times New Roman", Times, serif; font-size:11px; text-shadow:none; color:#000; background:#eee; border:1px solid rgba(0,0,0,.2) }
#skin-select ul li a.active, #skin-select ul li a.active:hover { background-color:#fff; outline:2px solid #000; border-color:transparent; }
#skin-select ul li a:hover { text-decoration:none; background:#e3e3e3; }

#skin-select .colors li { margin-bottom:0; }
#skin-select .colors a { display:block; width:4px; height:6px; line-height:100%; border:1px solid rgba(0,0,0,.2); }
#skin-select .colors a:hover { outline:2px solid #ccc; }

.skin-part { padding:12px 15px; }
.skin-part h3 { color:#000; text-shadow:none; margin-bottom:10px; }
.skin-part h3 small { margin-left:6px; color:#999; }
.skin-part h4 { font-size:1em; margin:4px 0; }

@media screen and (max-height: 800px) {
	#skin-select { top: 0px; }
}
@media screen and (max-width: 767px) {
	#skin-select { display:none; }
}


text:
import { Component } from '@angular/core';

@Component({
    selector: 'my-post',
    templateUrl: 'app/views/contact/contact.html',
})
export class PostComponent {

}


text:
//----------------------------------------------//
// Gamelogic Grids                              //
// http://www.gamelogic.co.za                   //
// Copyright (c) 2013 Gamelogic (Pty) Ltd       //
//----------------------------------------------//

using UnityEngine;

namespace Gamelogic.Grids
{
	// Documentation in Op.cs
	public partial class RectOp<TCell> : AbstractOp<ShapeStorageInfo<RectPoint>>
	{
		/**
			XXXXX
			XXXXX
			XXX
		*/
		[ShapeMethod]
		public RectShapeInfo<TCell> FixedWidth(int width, int cellCount)
		{
			var rawInfo = MakeShapeStorageInfo<RectPoint>(
				width,
				Mathf.CeilToInt(cellCount / (float)width),
				x => IsInsideFixedWidth(x, width, cellCount));

			return new RectShapeInfo<TCell>(rawInfo);
		}

		[ShapeMethod]
		public RectShapeInfo<TCell> FixedHeight(int height, int cellCount)
		{
			var rawInfo = MakeShapeStorageInfo<RectPoint>(
				Mathf.CeilToInt(cellCount / (float)height),
				height,
				x => IsInsideFixedHeight(x, height, cellCount));

			return new RectShapeInfo<TCell>(rawInfo);
		}

		/**
			Generates a grid in a rectangular shape.

			\param width The width of the grid.
			\param height The height of the grid.
		*/
		[ShapeMethod]
		public RectShapeInfo<TCell> Rectangle(int width, int height)
		{
			var rawInfow = MakeShapeStorageInfo<RectPoint>(
				width,
				height,
				x => IsInsideRect(x, width, height));

			return new RectShapeInfo<TCell>(rawInfow);
		}

		/**
			A synonym for Rectangle. Provided to support wrapped grids uniformly.

			@since 1.7
		*/
		[ShapeMethod]
		public RectShapeInfo<TCell> Parallelogram(int width, int height)
		{
			return Rectangle(width, height);
		}

		[ShapeMethod]
		public RectShapeInfo<TCell> CheckerBoard(int width, int height)
		{
			return CheckerBoard(width, height, true);
		}

		[ShapeMethod]
		public RectShapeInfo<TCell> CheckerBoard(int width, int height, bool includesOrigin)
		{
			var rawInfo = MakeShapeStorageInfo<RectPoint>(
				width, height,
				x => IsInsideCheckerBoard(x, width, height, includesOrigin));

			return new RectShapeInfo<TCell>(rawInfo);
		}

		public static bool IsInsideFixedWidth(RectPoint point, int width, int cellCount)
		{
			return point.X >= 0 && point.X < width && point.Y * width + point.X < cellCount;
		}

		public static bool IsInsideFixedHeight(RectPoint point, int height, int cellCount)
		{
			return point.Y >= 0 && point.Y < height && point.X * height + point.Y < cellCount;
		}

		public static bool IsInsideRect(RectPoint point, int width, int height)
		{
			return point.X >= 0 && point.X < width && point.Y >= 0 && point.Y < height;
		}

		public static bool IsInsideCheckerBoard(RectPoint point, int width, int height, bool includesOrigin)
		{
			return
				IsInsideRect(point, width, height) &&
				(Mathi.Mod(point.X + point.Y, 2) == (includesOrigin ? 0 : 1));
		}
	}
}


text:
from distutils.version import LooseVersion

from cassandra import ConsistencyLevel
from ccmlib.common import is_win

from dtest import Tester, debug, create_ks, create_cf
from tools.assertions import assert_length_equal
from tools.data import insert_c1c2
from tools.decorators import since
from tools.jmxutils import (JolokiaAgent, make_mbean,
                            remove_perf_disable_shared_mem)

@since("2.2", max_version="4")
class TestDeprecatedRepairAPI(Tester):
    """
    @jira_ticket CASSANDRA-9570

    Test if deprecated repair JMX API runs with expected parameters
    """

    def force_repair_async_1_test(self):
        """
        test forceRepairAsync(String keyspace, boolean isSequential,
                              Collection<String> dataCenters,
                              Collection<String> hosts,
                              boolean primaryRange, boolean fullRepair, String... columnFamilies)
        """
        opt = self._deprecated_repair_jmx("forceRepairAsync(java.lang.String,boolean,java.util.Collection,java.util.Collection,boolean,boolean,[Ljava.lang.String;)",
                                          ['ks', True, [], [], False, False, ["cf"]])
        self.assertEqual(opt["parallelism"], "parallel" if is_win() else "sequential", opt)
        self.assertEqual(opt["primary_range"], "false", opt)
        self.assertEqual(opt["incremental"], "true", opt)
        self.assertEqual(opt["job_threads"], "1", opt)
        self.assertEqual(opt["data_centers"], "[]", opt)
        self.assertEqual(opt["hosts"], "[]", opt)
        self.assertEqual(opt["column_families"], "[cf]", opt)

    def force_repair_async_2_test(self):
        """
        test forceRepairAsync(String keyspace, int parallelismDegree,
                              Collection<String> dataCenters,
                              Collection<String> hosts,
                              boolean primaryRange, boolean fullRepair, String... columnFamilies)
        """
        opt = self._deprecated_repair_jmx("forceRepairAsync(java.lang.String,int,java.util.Collection,java.util.Collection,boolean,boolean,[Ljava.lang.String;)",
                                          ['ks', 1, [], [], True, True, []])
        self.assertEqual(opt["parallelism"], "parallel", opt)
        self.assertEqual(opt["primary_range"], "true", opt)
        self.assertEqual(opt["incremental"], "false", opt)
        self.assertEqual(opt["job_threads"], "1", opt)
        self.assertEqual(opt["data_centers"], "[]", opt)
        self.assertEqual(opt["hosts"], "[]", opt)
        self.assertEqual(opt["column_families"], "[]", opt)

    def force_repair_async_3_test(self):
        """
        test forceRepairAsync(String keyspace, boolean isSequential,
                              boolean isLocal, boolean primaryRange,
                              boolean fullRepair, String... columnFamilies)
        """
        opt = self._deprecated_repair_jmx("forceRepairAsync(java.lang.String,boolean,boolean,boolean,boolean,[Ljava.lang.String;)",
                                          ['ks', False, False, False, False, ["cf"]])
        self.assertEqual(opt["parallelism"], "parallel", opt)
        self.assertEqual(opt["primary_range"], "false", opt)
        self.assertEqual(opt["incremental"], "true", opt)
        self.assertEqual(opt["job_threads"], "1", opt)
        self.assertEqual(opt["data_centers"], "[]", opt)
        self.assertEqual(opt["hosts"], "[]", opt)
        self.assertEqual(opt["column_families"], "[cf]", opt)

    def force_repair_range_async_1_test(self):
        """
        test forceRepairRangeAsync(String beginToken, String endToken,
                                   String keyspaceName, boolean isSequential,
                                   Collection<String> dataCenters,
                                   Collection<String> hosts, boolean fullRepair,
                                   String... columnFamilies)
        """
        opt = self._deprecated_repair_jmx("forceRepairRangeAsync(java.lang.String,java.lang.String,java.lang.String,boolean,java.util.Collection,java.util.Collection,boolean,[Ljava.lang.String;)",
                                          ["0", "1000", "ks", True, ["dc1"], [], False, ["cf"]])
        self.assertEqual(opt["parallelism"], "parallel" if is_win() else "sequential", opt)
        self.assertEqual(opt["primary_range"], "false", opt)
        self.assertEqual(opt["incremental"], "true", opt)
        self.assertEqual(opt["job_threads"], "1", opt)
        self.assertEqual(opt["data_centers"], "[dc1]", opt)
        self.assertEqual(opt["hosts"], "[]", opt)
        self.assertEqual(opt["ranges"], "1", opt)
        self.assertEqual(opt["column_families"], "[cf]", opt)

    def force_repair_range_async_2_test(self):
        """
        test forceRepairRangeAsync(String beginToken, String endToken,
                                   String keyspaceName, int parallelismDegree,
                                   Collection<String> dataCenters,
                                   Collection<String> hosts,
                                   boolean fullRepair, String... columnFamilies)
        """
        opt = self._deprecated_repair_jmx("forceRepairRangeAsync(java.lang.String,java.lang.String,java.lang.String,int,java.util.Collection,java.util.Collection,boolean,[Ljava.lang.String;)",
                                          ["0", "1000", "ks", 2, [], [], True, ["cf"]])
        self.assertEqual(opt["parallelism"], "parallel" if is_win() else "dc_parallel", opt)
        self.assertEqual(opt["primary_range"], "false", opt)
        self.assertEqual(opt["incremental"], "false", opt)
        self.assertEqual(opt["job_threads"], "1", opt)
        self.assertEqual(opt["data_centers"], "[]", opt)
        self.assertEqual(opt["hosts"], "[]", opt)
        self.assertEqual(opt["ranges"], "1", opt)
        self.assertEqual(opt["column_families"], "[cf]", opt)

    def force_repair_range_async_3_test(self):
        """
        test forceRepairRangeAsync(String beginToken, String endToken,
                                   String keyspaceName, boolean isSequential,
                                   boolean isLocal, boolean fullRepair,
                                   String... columnFamilies)
        """
        opt = self._deprecated_repair_jmx("forceRepairRangeAsync(java.lang.String,java.lang.String,java.lang.String,boolean,boolean,boolean,[Ljava.lang.String;)",
                                          ["0", "1000", "ks", True, True, True, ["cf"]])
        self.assertEqual(opt["parallelism"], "parallel" if is_win() else "sequential", opt)
        self.assertEqual(opt["primary_range"], "false", opt)
        self.assertEqual(opt["incremental"], "false", opt)
        self.assertEqual(opt["job_threads"], "1", opt)
        self.assertEqual(opt["data_centers"], "[dc1]", opt)
        self.assertEqual(opt["hosts"], "[]", opt)
        self.assertEqual(opt["ranges"], "1", opt)
        self.assertEqual(opt["column_families"], "[cf]", opt)

    def _deprecated_repair_jmx(self, method, arguments):
        """
        * Launch a two node, two DC cluster
        * Create a keyspace and table
        * Insert some data
        * Call the deprecated repair JMX API based on the arguments passed into this method
        * Check the node log to see if the correct repair was performed based on the jmx args
        """
        cluster = self.cluster

        debug("Starting cluster..")
        cluster.populate([1, 1])
        node1, node2 = cluster.nodelist()
        remove_perf_disable_shared_mem(node1)
        cluster.start()
        supports_pull_repair = cluster.version() >= LooseVersion('3.10')

        session = self.patient_cql_connection(node1)
        create_ks(session, 'ks', 2)
        create_cf(session, 'cf', read_repair=0.0, columns={'c1': 'text', 'c2': 'text'})

        insert_c1c2(session, n=1000, consistency=ConsistencyLevel.ALL)

        # Run repair
        mbean = make_mbean('db', 'StorageService')
        with JolokiaAgent(node1) as jmx:
            # assert repair runs and returns valid cmd number
            self.assertEqual(jmx.execute_method(mbean, method, arguments), 1)
        # wait for log to start
        node1.watch_log_for("Starting repair command")
        # get repair parameters from the log
        line = node1.grep_log(("Starting repair command #1" + (" \([^\)]+\)" if cluster.version() >= LooseVersion("3.10") else "") +
                               ", repairing keyspace ks with repair options \(parallelism: (?P<parallelism>\w+), primary range: (?P<pr>\w+), "
                               "incremental: (?P<incremental>\w+), job threads: (?P<jobs>\d+), ColumnFamilies: (?P<cfs>.+), dataCenters: (?P<dc>.+), "
                               "hosts: (?P<hosts>.+), # of ranges: (?P<ranges>\d+)(, pull repair: (?P<pullrepair>true|false))?\)"))

        assert_length_equal(line, 1)
        line, m = line[0]

        if supports_pull_repair:
            self.assertEqual(m.group("pullrepair"), "false", "Pull repair cannot be enabled through the deprecated API so the pull repair option should always be false.")

        return {"parallelism": m.group("parallelism"),
                "primary_range": m.group("pr"),
                "incremental": m.group("incremental"),
                "job_threads": m.group("jobs"),
                "column_families": m.group("cfs"),
                "data_centers": m.group("dc"),
                "hosts": m.group("hosts"),
                "ranges": m.group("ranges")}


text:
require 'socket'
require 'yajl'
require 'yajl/version' unless defined? Yajl::VERSION
require 'uri'

module Yajl
  # This module is for making HTTP requests to which the response bodies (and possibly requests in the near future)
  # are streamed directly into Yajl.
  class HttpStream

    # This Exception is thrown when an HTTP response isn't in ALLOWED_MIME_TYPES
    # and therefore cannot be parsed.
    class InvalidContentType < Exception; end
    class HttpError < StandardError

      attr_reader :message, :headers

      def initialize(message, headers)
        @message = message
        @headers = headers
      end
    end

    # The mime-type we expect the response to be. If it's anything else, we can't parse it
    # and an InvalidContentType is raised.
    ALLOWED_MIME_TYPES = ["application/json", "text/plain"]

    # Makes a basic HTTP GET request to the URI provided
    def self.get(uri, opts = {}, &block)
      request("GET", uri, opts, &block)
    end

    # Makes a basic HTTP GET request to the URI provided allowing the user to terminate the connection
    def get(uri, opts = {}, &block)
      initialize_socket(uri, opts)
      HttpStream::get(uri, opts, &block)
    rescue IOError => e
      raise e unless @intentional_termination
    end

    # Makes a basic HTTP POST request to the URI provided
    def self.post(uri, body, opts = {}, &block)
      request("POST", uri, opts.merge({:body => body}), &block)
    end

    # Makes a basic HTTP POST request to the URI provided allowing the user to terminate the connection
    def post(uri, body, opts = {}, &block)
      initialize_socket(uri, opts)
      HttpStream::post(uri, body, opts, &block)
    rescue IOError => e
      raise e unless @intentional_termination
    end

    # Makes a basic HTTP PUT request to the URI provided
    def self.put(uri, body, opts = {}, &block)
      request("PUT", uri, opts.merge({:body => body}), &block)
    end

    # Makes a basic HTTP PUT request to the URI provided allowing the user to terminate the connection
    def put(uri, body, opts = {}, &block)
      initialize_socket(uri, opts)
      HttpStream::put(uri, body, opts, &block)
    rescue IOError => e
      raise e unless @intentional_termination
    end

    # Makes a basic HTTP DELETE request to the URI provided
    def self.delete(uri, opts = {}, &block)
      request("DELETE", uri, opts, &block)
    end

    # Makes a basic HTTP DELETE request to the URI provided allowing the user to terminate the connection
    def delete(uri, opts = {}, &block)
      initialize_socket(uri, opts)
      HttpStream::delete(uri, opts, &block)
    rescue IOError => e
      raise e unless @intentional_termination
    end

    # Terminate a running HTTPStream instance
    def terminate
      @intentional_termination = true
      @socket.close
    end

    protected
      def self.request(method, uri, opts = {}, &block)
        if uri.is_a?(String)
          uri = URI.parse(uri)
        end

        user_agent = opts.has_key?('User-Agent') ? opts.delete(['User-Agent']) : "Yajl::HttpStream #{Yajl::VERSION}"
        if method == "POST" || method == "PUT"
          content_type = opts.has_key?('Content-Type') ? opts.delete(['Content-Type']) : "application/x-www-form-urlencoded"
          body = opts.delete(:body)
          if body.is_a?(Hash)
            body = body.keys.collect {|param| "#{URI.escape(param.to_s)}=#{URI.escape(body[param].to_s)}"}.join('&')
          end
        end

        socket = opts.has_key?(:socket) ? opts.delete(:socket) : TCPSocket.new(uri.host, uri.port)
        request = "#{method} #{uri.path}#{uri.query ? "?"+uri.query : nil} HTTP/1.1\r\n"
        request << "Host: #{uri.host}\r\n"
        request << "Authorization: Basic #{[uri.userinfo].pack('m').strip!}\r\n" unless uri.userinfo.nil?
        request << "User-Agent: #{user_agent}\r\n"
        request << "Accept: */*\r\n"
        if method == "POST" || method == "PUT"
          request << "Content-Length: #{body.length}\r\n"
          request << "Content-Type: #{content_type}\r\n"
        end
        encodings = []
        encodings << "bzip2" if defined?(Yajl::Bzip2)
        encodings << "gzip" if defined?(Yajl::Gzip)
        encodings << "deflate" if defined?(Yajl::Deflate)
        request << "Accept-Encoding: #{encodings.join(',')}\r\n" if encodings.any?
        request << "Accept-Charset: utf-8\r\n\r\n"
        if method == "POST" || method == "PUT"
          request << body
        end
        socket.write(request)
        response_head = {}
        response_head[:headers] = {}

        socket.each_line do |line|
          if line == "\r\n" # end of the headers
            break
          else
            header = line.split(": ")
            if header.size == 1
              header = header[0].split(" ")
              response_head[:version] = header[0]
              response_head[:code] = header[1].to_i
              response_head[:msg] = header[2]
              # this is the response code line
            else
              response_head[:headers][header[0]] = header[1].strip
            end
          end
        end

        if (response_head[:code] != 200)
          raise HttpError.new("Code 200 expected got #{response_head[:code]}", response_head[:headers])
        end

        parser = Yajl::Parser.new(opts)
        parser.on_parse_complete = block if block_given?
        if response_head[:headers]["Transfer-Encoding"] == 'chunked'
          if block_given?
            chunkLeft = 0
            while !socket.eof? && (line = socket.gets)
              break if line.match /^0.*?\r\n/
              next if line == "\r\n"
              size = line.hex
              json = socket.read(size)
              next if json.nil?
              chunkLeft = size-json.size
              if chunkLeft == 0
                parser << json
              else
                # received only part of the chunk, grab the rest
                parser << socket.read(chunkLeft)
              end
            end
          else
            raise Exception, "Chunked responses detected, but no block given to handle the chunks."
          end
        else
          content_type = response_head[:headers]["Content-Type"].split(';')
          content_type = content_type.first
          if ALLOWED_MIME_TYPES.include?(content_type)
            case response_head[:headers]["Content-Encoding"]
            when "gzip"
              return Yajl::Gzip::StreamReader.parse(socket, opts, &block)
            when "deflate"
              return Yajl::Deflate::StreamReader.parse(socket, opts.merge({:deflate_options => -Zlib::MAX_WBITS}), &block)
            when "bzip2"
              return Yajl::Bzip2::StreamReader.parse(socket, opts, &block)
            else
              return parser.parse(socket)
            end
          else
            raise InvalidContentType, "The response MIME type #{content_type}"
          end
        end
      ensure
        socket.close if !socket.nil? and !socket.closed?
      end

  private
    # Initialize socket and add it to the opts
    def initialize_socket(uri, opts = {})
      @socket = TCPSocket.new(uri.host, uri.port)
      opts.merge!({:socket => @socket})
      @intentional_termination = false
    end
  end
end


text:
var Phaser;
(function (Phaser) {
    /// <reference path="../Game.ts" />
    /// <reference path="Particle.ts" />
    /// <reference path="../geom/Vector2.ts" />
    /**
    * Phaser - AngleConstraint
    *
    * constrains 3 particles to an angle
    */
    (function (Verlet) {
        var AngleConstraint = (function () {
            /**
            * Creates a new AngleConstraint object.
            * @class AngleConstraint
            * @constructor
            * @param {Number} x The x coordinate of vector2
            * @param {Number} y The y coordinate of vector2
            * @return {AngleConstraint} This object
            **/
            function AngleConstraint(a, b, c, stiffness) {
                this.a = a;
                this.b = b;
                this.c = c;
                this.angle = this.b.pos.angle2(this.a.pos, this.c.pos);
                this.stiffness = stiffness;
            }
            AngleConstraint.prototype.relax = function (stepCoef) {
                var angle = this.b.pos.angle2(this.a.pos, this.c.pos);
                var diff = angle - this.angle;
                if(diff <= -Math.PI) {
                    diff += 2 * Math.PI;
                } else if(diff >= Math.PI) {
                    diff -= 2 * Math.PI;
                }
                diff *= stepCoef * this.stiffness;
                this.a.pos = this.a.pos.rotate(this.b.pos, diff);
                this.c.pos = this.c.pos.rotate(this.b.pos, -diff);
                this.b.pos = this.b.pos.rotate(this.a.pos, diff);
                this.b.pos = this.b.pos.rotate(this.c.pos, -diff);
            };
            AngleConstraint.prototype.render = function (ctx) {
                ctx.beginPath();
                ctx.moveTo(this.a.pos.x, this.a.pos.y);
                ctx.lineTo(this.b.pos.x, this.b.pos.y);
                ctx.lineTo(this.c.pos.x, this.c.pos.y);
                var tmp = ctx.lineWidth;
                ctx.lineWidth = 5;
                ctx.strokeStyle = "rgba(255,255,0,0.2)";
                ctx.stroke();
                ctx.lineWidth = tmp;
            };
            return AngleConstraint;
        })();
        Verlet.AngleConstraint = AngleConstraint;
    })(Phaser.Verlet || (Phaser.Verlet = {}));
    var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
//@ sourceMappingURL=AngleConstraint.js.map