<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "WorldInfo.h"

/* common implementation headers */
#include "global.h"
#include "Pack.h"
#include "Protocol.h"
#include "Intersect.h"

WorldInfo::WorldInfo() :
  maxHeight(0),
  database(NULL)
{
  size[0] = 400.0f;
  size[1] = 400.0f;
  gravity = -9.81f;
}

WorldInfo::~WorldInfo()
{
  delete[] database;
}

void WorldInfo::addWall(float x, float y, float z, float r, float w, float h)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = walls.size();
  walls.resize(i+1);
  walls[i].pos[0] = x;
  walls[i].pos[1] = y;
  walls[i].pos[2] = z;
  walls[i].rotation = r;
  walls[i].size[0] = w;
  // no depth to walls
  walls[i].size[1] = 0.0f;
  walls[i].size[2] = h;
}

void WorldInfo::addBox(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = boxes.size();
  boxes.resize(i+1);
  boxes[i].pos[0] = x;
  boxes[i].pos[1] = y;
  boxes[i].pos[2] = z;
  boxes[i].rotation = r;
  boxes[i].size[0] = w;
  boxes[i].size[1] = d;
  boxes[i].size[2] = h;
  boxes[i].driveThrough = drive;
  boxes[i].shootThrough = shoot;
}

void WorldInfo::addPyramid(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot, bool flipZ)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = pyramids.size();
  pyramids.resize(i+1);
  pyramids[i].pos[0] = x;
  pyramids[i].pos[1] = y;
  pyramids[i].pos[2] = z;
  pyramids[i].rotation = r;
  pyramids[i].size[0] = w;
  pyramids[i].size[1] = d;
  pyramids[i].size[2] = h;
  pyramids[i].driveThrough = drive;
  pyramids[i].shootThrough = shoot;
  pyramids[i].flipZ = flipZ;
}

void WorldInfo::addTeleporter(float x, float y, float z, float r, float w, float d, float h, float b, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = teleporters.size();
  teleporters.resize(i+1);
  teleporters[i].pos[0] = x;
  teleporters[i].pos[1] = y;
  teleporters[i].pos[2] = z;
  teleporters[i].rotation = r;
  teleporters[i].size[0] = w;
  teleporters[i].size[1] = d;
  teleporters[i].size[2] = h;
  teleporters[i].driveThrough = drive;
  teleporters[i].shootThrough = shoot;
  teleporters[i].border = b;
  // default link through
  teleporters[i].to[0] = i * 2 + 1;
  teleporters[i].to[1] = i * 2;
}

void WorldInfo::addBase(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = bases.size();
  bases.resize(i+1);
  bases[i].pos[0] = x;
  bases[i].pos[1] = y;
  bases[i].pos[2] = z;
  bases[i].rotation = r;
  bases[i].size[0] = w;
  bases[i].size[1] = d;
  bases[i].size[2] = h;
  bases[i].driveThrough = drive;
  bases[i].shootThrough = shoot;
}

void WorldInfo::addLink(int from, int to)
{
  // discard links to/from teleporters that don't exist
  if ((unsigned(from) > teleporters.size() * 2 + 1) ||
     (unsigned(to) > teleporters.size() * 2 + 1)) {
    DEBUG1("Warning: bad teleporter link dropped from=%d to=%d\n", from, to);
  } else {
    teleporters[from / 2].to[from % 2] = to;
  }
}

void WorldInfo::addZone(const CustomZone *zone)
{
  entryZones.addZone( zone );
}

float WorldInfo::getMaxWorldHeight()
{
  return maxHeight;
}

bool WorldInfo::rectHitCirc(float dx, float dy, const float *p, float r) const
{
  // Algorithm from Graphics Gems, pp51-53.
  const float rr = r * r, rx = -p[0], ry = -p[1];
  if (rx + dx < 0.0f) // west of rect
    if (ry + dy < 0.0f) //  sw corner
      return (rx + dx) * (rx + dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  nw corner
      return (rx + dx) * (rx + dx) + (ry - dy) * (ry - dy) < rr;
    else //  due west
      return rx + dx > -r;

  else if (rx - dx > 0.0f) // east of rect
    if (ry + dy < 0.0f) //  se corner
      return (rx - dx) * (rx - dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  ne corner
      return (rx - dx) * (rx - dx) + (ry - dy) * (ry - dy) < rr;
    else //  due east
      return rx - dx < r;

  else if (ry + dy < 0.0f) // due south
    return ry + dy > -r;

  else if (ry - dy > 0.0f) // due north
    return ry - dy < r;

  // circle origin in rect
  return true;
}

bool WorldInfo::inRect(const float *p1, float angle, const float *size, float x, float y, float r) const
{
  // translate origin
  float pa[2];
  pa[0] = x - p1[0];
  pa[1] = y - p1[1];

  // rotate
  float pb[2];
  const float c = cosf(-angle), s = sinf(-angle);
  pb[0] = c * pa[0] - s * pa[1];
  pb[1] = c * pa[1] + s * pa[0];

  // do test
  return rectHitCirc(size[0], size[1], pb, r);
}

InBuildingType WorldInfo::inBuilding(ObstacleLocation **location,
				     float x, float y, float z, float r,
				     float height)
{
  ObstacleLocationList::iterator it;
  PyramidList::iterator pyrit;
  TeleporterList::iterator telit;

  if (height < Epsilon)
    height = Epsilon;

  for (it = bases.begin(); it != bases.end(); ++it) {
    ObstacleLocation &base = *it;
    if ((base.pos[2] < (z + height))
	&& ((base.pos[2] + base.size[2]) > z)
	&& (inRect(base.pos, base.rotation, base.size, x, y, r))) {
      if (location != NULL)
	*location = &base;
      return IN_BASE;
    }
  }
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    if ((box.pos[2] < (z + height))
	&& ((box.pos[2] + box.size[2]) > z)
	&& (inRect(box.pos, box.rotation, box.size, x, y, r))) {
      if (location != NULL)
	*location = &box;
      if (box.driveThrough) return IN_BOX_DRIVETHROUGH;
      else return IN_BOX_NOTDRIVETHROUGH;
    }
  }
  for (pyrit = pyramids.begin(); pyrit != pyramids.end(); ++pyrit) {
    ObstacleLocation &pyr = *pyrit;
    if ((pyr.pos[2] < (z + height))
	&& ((pyr.pos[2] + pyr.size[2]) > z)
	&& (inRect(pyr.pos, pyr.rotation, pyr.size,x,y,r))) {
      if (location != NULL)
	*location = &pyr;
      return IN_PYRAMID;
    }
  }
  for (telit = teleporters.begin(); telit != teleporters.end(); ++telit) {
    Teleporter &tele = *telit;
    if ((tele.pos[2] < (z + height))
	&& ((tele.pos[2] + tele.size[2]) > z)
	&& (inRect(tele.pos, tele.rotation, tele.size, x, y, r))) {
      static ObstacleLocation __teleporter;
      __teleporter = tele;
      if (location != NULL)
	*location = &__teleporter;
      return IN_TELEPORTER;
    }
  }

  if (location != NULL)
    *location = (ObstacleLocation *)NULL;
  return NOT_IN_BUILDING;
}

bool WorldInfo::getZonePoint(const std::string &qualifier, float *pt)
{
  ObstacleLocation *loc;
  InBuildingType type;

  if (!entryZones.getZonePoint(qualifier, pt))
    return false;

  type = inBuilding(&loc, pt[0], pt[1], 0.0f, 1.0f, pt[2]);
  if (type == NOT_IN_BUILDING)
    pt[2] = 0.0f;
  else
    pt[2] = loc->pos[2];
  return true;
}

void WorldInfo::finishWorld()
{
  entryZones.calculateQualifierLists();
}

int WorldInfo::packDatabase()
{
  databaseSize =
    (2 + 2 + WorldCodeWallSize) * walls.size() +
    (2 + 2 + WorldCodeBoxSize) * boxes.size() +
    (2 + 2 + WorldCodePyramidSize) * pyramids.size() +
    (2 + 2 + WorldCodeTeleporterSize) * teleporters.size() +
    (2 + 2 + WorldCodeLinkSize) * 2 * teleporters.size();
  database = new char[databaseSize];
  void *databasePtr = database;

  // define i out here so we avoid the loop variable scope debates
  ObstacleLocationList::iterator it;
  unsigned char	bitMask;

  // add walls
  for (it = walls.begin(); it != walls.end(); ++it) {
    ObstacleLocation &wall = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeWallSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeWall);
    databasePtr = nboPackVector(databasePtr, wall.pos);
    databasePtr = nboPackFloat(databasePtr, wall.rotation);
    databasePtr = nboPackFloat(databasePtr, wall.size[0]);
    // walls have no depth
    databasePtr = nboPackFloat(databasePtr, wall.size[2]);
  }

  // add boxes
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeBoxSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeBox);
    databasePtr = nboPackVector(databasePtr, box.pos);
    databasePtr = nboPackFloat(databasePtr, box.rotation);
    databasePtr = nboPackVector(databasePtr, box.size);
    bitMask = 0;
    if (box.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (box.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add pyramids
  for (PyramidList::iterator pyr_it = pyramids.begin(); pyr_it != pyramids.end(); ++pyr_it) {
    Pyramid &pyr = *pyr_it;
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramidSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramid);
    databasePtr = nboPackVector(databasePtr, pyr.pos);
    databasePtr = nboPackFloat(databasePtr, pyr.rotation);
    databasePtr = nboPackVector(databasePtr, pyr.size);
    bitMask = 0;
    if (pyr.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (pyr.shootThrough)
      bitMask |= _SHOOT_THRU;
    if (pyr.flipZ)
      bitMask |= _FLIP_Z;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add teleporters
  int i = 0;
  for (TeleporterList::iterator telit = teleporters.begin(); telit != teleporters.end(); ++telit, i++) {
    Teleporter &tele = *telit;
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporterSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporter);
    databasePtr = nboPackVector(databasePtr, tele.pos);
    databasePtr = nboPackFloat(databasePtr, tele.rotation);
    databasePtr = nboPackVector(databasePtr, tele.size);
    databasePtr = nboPackFloat(databasePtr, tele.border);
    bitMask = 0;
    if (tele.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (tele.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
    // and each link
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[0]));
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2 + 1));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[1]));
  }

  return 1;
}

void *WorldInfo::getDatabase() const
{
  return database;
}

int WorldInfo::getDatabaseSize() const
{
  return databaseSize;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>put random teleporters back<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "WorldInfo.h"

/* common implementation headers */
#include "global.h"
#include "Pack.h"
#include "Protocol.h"
#include "Intersect.h"

WorldInfo::WorldInfo() :
  maxHeight(0),
  database(NULL)
{
  size[0] = 400.0f;
  size[1] = 400.0f;
  gravity = -9.81f;
}

WorldInfo::~WorldInfo()
{
  delete[] database;
}

void WorldInfo::addWall(float x, float y, float z, float r, float w, float h)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = walls.size();
  walls.resize(i+1);
  walls[i].pos[0] = x;
  walls[i].pos[1] = y;
  walls[i].pos[2] = z;
  walls[i].rotation = r;
  walls[i].size[0] = w;
  // no depth to walls
  walls[i].size[1] = 0.0f;
  walls[i].size[2] = h;
}

void WorldInfo::addBox(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = boxes.size();
  boxes.resize(i+1);
  boxes[i].pos[0] = x;
  boxes[i].pos[1] = y;
  boxes[i].pos[2] = z;
  boxes[i].rotation = r;
  boxes[i].size[0] = w;
  boxes[i].size[1] = d;
  boxes[i].size[2] = h;
  boxes[i].driveThrough = drive;
  boxes[i].shootThrough = shoot;
}

void WorldInfo::addPyramid(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot, bool flipZ)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = pyramids.size();
  pyramids.resize(i+1);
  pyramids[i].pos[0] = x;
  pyramids[i].pos[1] = y;
  pyramids[i].pos[2] = z;
  pyramids[i].rotation = r;
  pyramids[i].size[0] = w;
  pyramids[i].size[1] = d;
  pyramids[i].size[2] = h;
  pyramids[i].driveThrough = drive;
  pyramids[i].shootThrough = shoot;
  pyramids[i].flipZ = flipZ;
}

void WorldInfo::addTeleporter(float x, float y, float z, float r, float w, float d, float h, float b, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = teleporters.size();
  teleporters.resize(i+1);
  teleporters[i].pos[0] = x;
  teleporters[i].pos[1] = y;
  teleporters[i].pos[2] = z;
  teleporters[i].rotation = r;
  teleporters[i].size[0] = w;
  teleporters[i].size[1] = d;
  teleporters[i].size[2] = h;
  teleporters[i].driveThrough = drive;
  teleporters[i].shootThrough = shoot;
  teleporters[i].border = b;
  // default link through
  teleporters[i].to[0] = i * 2 + 1;
  teleporters[i].to[1] = i * 2;
}

void WorldInfo::addBase(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = bases.size();
  bases.resize(i+1);
  bases[i].pos[0] = x;
  bases[i].pos[1] = y;
  bases[i].pos[2] = z;
  bases[i].rotation = r;
  bases[i].size[0] = w;
  bases[i].size[1] = d;
  bases[i].size[2] = h;
  bases[i].driveThrough = drive;
  bases[i].shootThrough = shoot;
}

void WorldInfo::addLink(int from, int to)
{
  // discard links to/from teleporters that don't exist
  // note that -1 "to" means the client picks one at random
  if ((unsigned(from) > teleporters.size() * 2 + 1) ||
     ((unsigned(to) > teleporters.size() * 2 + 1) && (to != -1))) {
    DEBUG1("Warning: bad teleporter link dropped from=%d to=%d\n", from, to);
  } else {
    teleporters[from / 2].to[from % 2] = to;
  }
}

void WorldInfo::addZone(const CustomZone *zone)
{
  entryZones.addZone( zone );
}

float WorldInfo::getMaxWorldHeight()
{
  return maxHeight;
}

bool WorldInfo::rectHitCirc(float dx, float dy, const float *p, float r) const
{
  // Algorithm from Graphics Gems, pp51-53.
  const float rr = r * r, rx = -p[0], ry = -p[1];
  if (rx + dx < 0.0f) // west of rect
    if (ry + dy < 0.0f) //  sw corner
      return (rx + dx) * (rx + dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  nw corner
      return (rx + dx) * (rx + dx) + (ry - dy) * (ry - dy) < rr;
    else //  due west
      return rx + dx > -r;

  else if (rx - dx > 0.0f) // east of rect
    if (ry + dy < 0.0f) //  se corner
      return (rx - dx) * (rx - dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  ne corner
      return (rx - dx) * (rx - dx) + (ry - dy) * (ry - dy) < rr;
    else //  due east
      return rx - dx < r;

  else if (ry + dy < 0.0f) // due south
    return ry + dy > -r;

  else if (ry - dy > 0.0f) // due north
    return ry - dy < r;

  // circle origin in rect
  return true;
}

bool WorldInfo::inRect(const float *p1, float angle, const float *size, float x, float y, float r) const
{
  // translate origin
  float pa[2];
  pa[0] = x - p1[0];
  pa[1] = y - p1[1];

  // rotate
  float pb[2];
  const float c = cosf(-angle), s = sinf(-angle);
  pb[0] = c * pa[0] - s * pa[1];
  pb[1] = c * pa[1] + s * pa[0];

  // do test
  return rectHitCirc(size[0], size[1], pb, r);
}

InBuildingType WorldInfo::inBuilding(ObstacleLocation **location,
				     float x, float y, float z, float r,
				     float height)
{
  ObstacleLocationList::iterator it;
  PyramidList::iterator pyrit;
  TeleporterList::iterator telit;

  if (height < Epsilon)
    height = Epsilon;

  for (it = bases.begin(); it != bases.end(); ++it) {
    ObstacleLocation &base = *it;
    if ((base.pos[2] < (z + height))
	&& ((base.pos[2] + base.size[2]) > z)
	&& (inRect(base.pos, base.rotation, base.size, x, y, r))) {
      if (location != NULL)
	*location = &base;
      return IN_BASE;
    }
  }
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    if ((box.pos[2] < (z + height))
	&& ((box.pos[2] + box.size[2]) > z)
	&& (inRect(box.pos, box.rotation, box.size, x, y, r))) {
      if (location != NULL)
	*location = &box;
      if (box.driveThrough) return IN_BOX_DRIVETHROUGH;
      else return IN_BOX_NOTDRIVETHROUGH;
    }
  }
  for (pyrit = pyramids.begin(); pyrit != pyramids.end(); ++pyrit) {
    ObstacleLocation &pyr = *pyrit;
    if ((pyr.pos[2] < (z + height))
	&& ((pyr.pos[2] + pyr.size[2]) > z)
	&& (inRect(pyr.pos, pyr.rotation, pyr.size,x,y,r))) {
      if (location != NULL)
	*location = &pyr;
      return IN_PYRAMID;
    }
  }
  for (telit = teleporters.begin(); telit != teleporters.end(); ++telit) {
    Teleporter &tele = *telit;
    if ((tele.pos[2] < (z + height))
	&& ((tele.pos[2] + tele.size[2]) > z)
	&& (inRect(tele.pos, tele.rotation, tele.size, x, y, r))) {
      static ObstacleLocation __teleporter;
      __teleporter = tele;
      if (location != NULL)
	*location = &__teleporter;
      return IN_TELEPORTER;
    }
  }

  if (location != NULL)
    *location = (ObstacleLocation *)NULL;
  return NOT_IN_BUILDING;
}

bool WorldInfo::getZonePoint(const std::string &qualifier, float *pt)
{
  ObstacleLocation *loc;
  InBuildingType type;

  if (!entryZones.getZonePoint(qualifier, pt))
    return false;

  type = inBuilding(&loc, pt[0], pt[1], 0.0f, 1.0f, pt[2]);
  if (type == NOT_IN_BUILDING)
    pt[2] = 0.0f;
  else
    pt[2] = loc->pos[2];
  return true;
}

void WorldInfo::finishWorld()
{
  entryZones.calculateQualifierLists();
}

int WorldInfo::packDatabase()
{
  databaseSize =
    (2 + 2 + WorldCodeWallSize) * walls.size() +
    (2 + 2 + WorldCodeBoxSize) * boxes.size() +
    (2 + 2 + WorldCodePyramidSize) * pyramids.size() +
    (2 + 2 + WorldCodeTeleporterSize) * teleporters.size() +
    (2 + 2 + WorldCodeLinkSize) * 2 * teleporters.size();
  database = new char[databaseSize];
  void *databasePtr = database;

  // define i out here so we avoid the loop variable scope debates
  ObstacleLocationList::iterator it;
  unsigned char	bitMask;

  // add walls
  for (it = walls.begin(); it != walls.end(); ++it) {
    ObstacleLocation &wall = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeWallSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeWall);
    databasePtr = nboPackVector(databasePtr, wall.pos);
    databasePtr = nboPackFloat(databasePtr, wall.rotation);
    databasePtr = nboPackFloat(databasePtr, wall.size[0]);
    // walls have no depth
    databasePtr = nboPackFloat(databasePtr, wall.size[2]);
  }

  // add boxes
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeBoxSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeBox);
    databasePtr = nboPackVector(databasePtr, box.pos);
    databasePtr = nboPackFloat(databasePtr, box.rotation);
    databasePtr = nboPackVector(databasePtr, box.size);
    bitMask = 0;
    if (box.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (box.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add pyramids
  for (PyramidList::iterator pyr_it = pyramids.begin(); pyr_it != pyramids.end(); ++pyr_it) {
    Pyramid &pyr = *pyr_it;
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramidSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramid);
    databasePtr = nboPackVector(databasePtr, pyr.pos);
    databasePtr = nboPackFloat(databasePtr, pyr.rotation);
    databasePtr = nboPackVector(databasePtr, pyr.size);
    bitMask = 0;
    if (pyr.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (pyr.shootThrough)
      bitMask |= _SHOOT_THRU;
    if (pyr.flipZ)
      bitMask |= _FLIP_Z;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add teleporters
  int i = 0;
  for (TeleporterList::iterator telit = teleporters.begin(); telit != teleporters.end(); ++telit, i++) {
    Teleporter &tele = *telit;
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporterSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporter);
    databasePtr = nboPackVector(databasePtr, tele.pos);
    databasePtr = nboPackFloat(databasePtr, tele.rotation);
    databasePtr = nboPackVector(databasePtr, tele.size);
    databasePtr = nboPackFloat(databasePtr, tele.border);
    bitMask = 0;
    if (tele.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (tele.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
    // and each link
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[0]));
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2 + 1));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[1]));
  }

  return 1;
}

void *WorldInfo::getDatabase() const
{
  return database;
}

int WorldInfo::getDatabaseSize() const
{
  return databaseSize;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Backtrace.h"

#ifndef _WIN32
#include <execinfo.h>
#include <cxxabi.h>
#endif

#include <stdlib.h>
#include <iostream>
#include <stdio.h>

using namespace std;

namespace avg {

void dumpBacktrace()
{
#ifndef _WIN32
    vector<string> sFuncs;
    getBacktrace(sFuncs);
    vector<string>::iterator it = sFuncs.begin();
    ++it;
    for (; it != sFuncs.end(); ++it) {
        cerr << "  " << *it << endl;
    }
#endif
}

string funcNameFromLine(const string& sLine)
{
    try {
#ifdef __APPLE__
        string::size_type addressPos = sLine.find("0x");
        string::size_type namePos = sLine.find(" ", addressPos);
        namePos++;
        string::size_type nameEndPos = sLine.find(" ", namePos);
#else
        string::size_type namePos = sLine.find("(");
        namePos++;
        string::size_type nameEndPos = sLine.find_first_of(")+", namePos);
#endif
        return sLine.substr(namePos, nameEndPos-namePos);
    } catch (exception&) {
        return sLine;
    }
}

void consolidateRepeatedLines(vector<string>& sFuncs, unsigned& i, unsigned numSameLines)
{
    unsigned firstSameLine = i - numSameLines;
    sFuncs[firstSameLine+1] = "    [...]";
    sFuncs.erase(sFuncs.begin()+firstSameLine+2, sFuncs.begin()+i-1);
    i = firstSameLine + 3;
}

void getBacktrace(vector<string>& sFuncs)
{
#ifndef _WIN32
    void* callstack[128];
    int numFrames = backtrace(callstack, 128);
    char** ppszLines = backtrace_symbols(callstack, numFrames);
    for (int i = 1; i < numFrames; ++i) {
        string sLine = ppszLines[i];
        string sFuncName = funcNameFromLine(sLine);
        int result;
        char * pszDemangledFuncName = abi::__cxa_demangle(sFuncName.c_str(), 0, 0,
                &result);
        if (!result) {
            sFuncName = pszDemangledFuncName;
            free(pszDemangledFuncName);
        }
        char szLineNum[10];
        sprintf(szLineNum, "%3d", i);
        sFuncs.push_back(string(szLineNum)+" "+sFuncName);
    }
    free(ppszLines);

    unsigned numSameLines = 1;
    unsigned i = 1;
    for (i = 1; i < sFuncs.size(); ++i) {
        if (sFuncs[i].substr(4, string::npos) == sFuncs[i-1].substr(4, string::npos)) {
            numSameLines++;
        } else {
            if (numSameLines > 3) {
                consolidateRepeatedLines(sFuncs, i, numSameLines);
            }
            numSameLines = 1;
        }
    }
    if (numSameLines > 2) {
        consolidateRepeatedLines(sFuncs, i, numSameLines);
    }
#endif
}

}

<commit_msg>Fix possible out-of-bounds buffer write<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Backtrace.h"

#ifndef _WIN32
#include <execinfo.h>
#include <cxxabi.h>
#endif

#include <stdlib.h>
#include <iostream>
#include <stdio.h>

using namespace std;

namespace avg {

void dumpBacktrace()
{
#ifndef _WIN32
    vector<string> sFuncs;
    getBacktrace(sFuncs);
    vector<string>::iterator it = sFuncs.begin();
    ++it;
    for (; it != sFuncs.end(); ++it) {
        cerr << "  " << *it << endl;
    }
#endif
}

string funcNameFromLine(const string& sLine)
{
    try {
#ifdef __APPLE__
        string::size_type addressPos = sLine.find("0x");
        string::size_type namePos = sLine.find(" ", addressPos);
        namePos++;
        string::size_type nameEndPos = sLine.find(" ", namePos);
#else
        string::size_type namePos = sLine.find("(");
        namePos++;
        string::size_type nameEndPos = sLine.find_first_of(")+", namePos);
#endif
        return sLine.substr(namePos, nameEndPos-namePos);
    } catch (exception&) {
        return sLine;
    }
}

void consolidateRepeatedLines(vector<string>& sFuncs, unsigned& i, unsigned numSameLines)
{
    unsigned firstSameLine = i - numSameLines;
    sFuncs[firstSameLine+1] = "    [...]";
    sFuncs.erase(sFuncs.begin()+firstSameLine+2, sFuncs.begin()+i-1);
    i = firstSameLine + 3;
}

void getBacktrace(vector<string>& sFuncs)
{
#ifndef _WIN32
    void* callstack[128];
    int numFrames = backtrace(callstack, 128);
    char** ppszLines = backtrace_symbols(callstack, numFrames);
    for (int i = 1; i < numFrames; ++i) {
        string sLine = ppszLines[i];
        string sFuncName = funcNameFromLine(sLine);
        int result;
        char * pszDemangledFuncName = abi::__cxa_demangle(sFuncName.c_str(), 0, 0,
                &result);
        if (!result) {
            sFuncName = pszDemangledFuncName;
            free(pszDemangledFuncName);
        }
        char szLineNum[12];
        snprintf(szLineNum, 11, "%3d", i);
        sFuncs.push_back(string(szLineNum)+" "+sFuncName);
    }
    free(ppszLines);

    unsigned numSameLines = 1;
    unsigned i = 1;
    for (i = 1; i < sFuncs.size(); ++i) {
        if (sFuncs[i].substr(4, string::npos) == sFuncs[i-1].substr(4, string::npos)) {
            numSameLines++;
        } else {
            if (numSameLines > 3) {
                consolidateRepeatedLines(sFuncs, i, numSameLines);
            }
            numSameLines = 1;
        }
    }
    if (numSameLines > 2) {
        consolidateRepeatedLines(sFuncs, i, numSameLines);
    }
#endif
}

}

<|endoftext|>


<commit_before>#include <yuni/yuni.h>
#include <yuni/string.h>
#include <yuni/core/system/main.h>
#include <yuni/core/system/environment.h>
#include <yuni/io/file.h>
#include <nany/nany.h>
#include <memory>
#include <iostream>
#include <cassert>
#include <limits.h>

using namespace Yuni;

static const char* argv0 = "";

struct Options
{
	//! Verbose mode
	bool verbose = false;
	//! Maximum number of jobs
	uint32_t jobs = 1;
	//! Memory limit (zero means unlimited)
	size_t memoryLimit = 0;
};

static int printUsage(const char* const argv0)
{
	std::cout
		<< "Usage: " << argv0 << " [options] file...\n"
		<< "Options:\n"
		<< "  --bugreport       Display some useful information to report a bug\n"
		<< "                    (https://github.com/nany-lang/nany/issues/new)\n"
		<< "  --help, -h        Display this information\n"
		<< "  --version, -v     Print the version\n\n";
	return EXIT_SUCCESS;
}

static int printBugReportInfo()
{
	auto* text = nany_get_info_for_bugreport();
	if (text)
	{
		std::cout << text;
		::free(text);
		return 0;
	}
	return EXIT_FAILURE;
}

static int printVersion()
{
	std::cout << nany_version() << '\n';
	return EXIT_SUCCESS;
}

static int unknownOption(const AnyString& name)
{
	std::cerr << argv0 << ": unknown option '" << name << "'\n";
	return EXIT_FAILURE;
}

static inline bool initializeContext(nycontext_t& ctx, const Options& options)
{
	size_t memoryLimit = options.memoryLimit;
	if (memoryLimit == 0)
		memoryLimit = static_cast<size_t>(System::Environment::ReadAsUInt64("NANY_MEMORY_LIMIT", 0));

	if (memoryLimit == 0)
	{
		// internal: using nullptr should be slighty faster than
		// using 'nany_memalloc_init_default' + custom memalloc as parameter
		if (nyfalse == nany_initialize(&ctx, nullptr, nullptr))
			return false;
	}
	else
	{
		nycontext_memory_t memalloc;
		nany_mem_alloc_init_with_limit(&memalloc, memoryLimit);
		if (nyfalse == nany_initialize(&ctx, nullptr, &memalloc))
			return false;
	}

	// for concurrent build, create a queue service if more than
	// one concurrent job is allowed
	if (options.jobs > 1)
		ctx.mt.queueservice = nany_queueservice_create();
	return true;
}

static inline int execute(int argc, char** argv, const Options& options)
{
	assert(argc >= 1);
	int exitstatus = 66;

	// nany context
	nycontext_t ctx;
	bool init = initializeContext(ctx, options);
	if (YUNI_UNLIKELY(not init))
		return exitstatus;

	// sources
	String scriptfile;
	IO::Canonicalize(scriptfile, argv[0]);
	auto r = nany_source_add_from_file_n(&ctx, scriptfile.c_str(), scriptfile.size());
	init = (r == nytrue);

	// building
	bool buildstatus;
	if (init)
	{
		nyreport_t* report = nullptr;
		buildstatus = (nany_build(&ctx, &report) == nytrue);

		// report printing
		// if an error has occured or if in verbose mode
		if (YUNI_UNLIKELY((not buildstatus) or options.verbose))
			(buildstatus ? nany_report_print_stdout : nany_report_print_stderr)(report);

		nany_report_unref(&report);
	}
	else
		buildstatus = false;

	// executing the program
	if (buildstatus)
	{
		if (argc == 1)
		{
			const char* nargv[] = { scriptfile.c_str(), nullptr };
			exitstatus = nany_run_main(&ctx, 1, nargv);
		}
		else
		{
			auto** nargv = (const char**)::malloc(((size_t) argc + 1) * sizeof(const char**));
			if (nargv)
			{
				for (int i = 1; i < argc; ++i)
					nargv[i] = argv[i];
				nargv[0]    = scriptfile.c_str();
				nargv[argc] = nullptr;

				exitstatus = nany_run_main(&ctx, argc, nargv);
				free(nargv);
			}
		}
	}

	nany_uninitialize(&ctx);
	return exitstatus;
}

YUNI_MAIN_CONSOLE(argc, argv)
{
	argv0 = argv[0];
	if (YUNI_UNLIKELY(argc <= 1))
	{
		std::cerr << argv0 << ": no input script file\n";
		return EXIT_FAILURE;
	}

	try
	{
		Options options;
		int firstarg = -1;
		for (int i = 1; i < argc; ++i)
		{
			const char* const carg = argv[i];
			if (carg[0] == '-')
			{
				if (carg[1] == '-')
				{
					if (carg[2] != '\0') // to handle '--' option
					{
						AnyString arg{carg};
						if (arg == "--help")
							return printUsage(argv[0]);
						if (arg == "--version")
							return printVersion();
						if (arg == "--bugreport")
							return printBugReportInfo();
						if (arg == "--verbose")
						{
							options.verbose = true;
							continue;
						}
						return unknownOption(arg);
					}
					else
					{
						firstarg = i + 1;
						break; // nothing must interpreted after '--'
					}
				}
				else
				{
					AnyString arg{carg};
					if (arg == "-h")
						return printUsage(argv[0]);
					if (arg == "-v")
						return printVersion();
					return unknownOption(arg);
				}
			}

			firstarg = i;
			break;
		}

		//
		// -- execute the script
		//
		return execute(argc - firstarg, argv + firstarg, options);
	}
	catch (std::bad_alloc&)
	{
		std::cerr << '\n' << argv0 << ": error: failed to allocate memory\n";
	}
	catch (...)
	{
		std::cerr << '\n' << argv0 << ": error: unhandled exception\n";
	}
	return EXIT_FAILURE;
}
<commit_msg>nany: temporary revert to standard 'main'<commit_after>#include <yuni/yuni.h>
#include <yuni/string.h>
#include <yuni/core/system/main.h>
#include <yuni/core/system/environment.h>
#include <yuni/io/file.h>
#include <nany/nany.h>
#include <memory>
#include <iostream>
#include <cassert>
#include <limits.h>

using namespace Yuni;

static const char* argv0 = "";

struct Options
{
	//! Verbose mode
	bool verbose = false;
	//! Maximum number of jobs
	uint32_t jobs = 1;
	//! Memory limit (zero means unlimited)
	size_t memoryLimit = 0;
};

static int printUsage(const char* const argv0)
{
	std::cout
		<< "Usage: " << argv0 << " [options] file...\n"
		<< "Options:\n"
		<< "  --bugreport       Display some useful information to report a bug\n"
		<< "                    (https://github.com/nany-lang/nany/issues/new)\n"
		<< "  --help, -h        Display this information\n"
		<< "  --version, -v     Print the version\n\n";
	return EXIT_SUCCESS;
}

static int printBugReportInfo()
{
	auto* text = nany_get_info_for_bugreport();
	if (text)
	{
		std::cout << text;
		::free(text);
		return 0;
	}
	return EXIT_FAILURE;
}

static int printVersion()
{
	std::cout << nany_version() << '\n';
	return EXIT_SUCCESS;
}

static int unknownOption(const AnyString& name)
{
	std::cerr << argv0 << ": unknown option '" << name << "'\n";
	return EXIT_FAILURE;
}

static inline bool initializeContext(nycontext_t& ctx, const Options& options)
{
	size_t memoryLimit = options.memoryLimit;
	if (memoryLimit == 0)
		memoryLimit = static_cast<size_t>(System::Environment::ReadAsUInt64("NANY_MEMORY_LIMIT", 0));

	if (memoryLimit == 0)
	{
		// internal: using nullptr should be slighty faster than
		// using 'nany_memalloc_init_default' + custom memalloc as parameter
		if (nyfalse == nany_initialize(&ctx, nullptr, nullptr))
			return false;
	}
	else
	{
		nycontext_memory_t memalloc;
		nany_mem_alloc_init_with_limit(&memalloc, memoryLimit);
		if (nyfalse == nany_initialize(&ctx, nullptr, &memalloc))
			return false;
	}

	// for concurrent build, create a queue service if more than
	// one concurrent job is allowed
	if (options.jobs > 1)
		ctx.mt.queueservice = nany_queueservice_create();
	return true;
}

static inline int execute(int argc, char** argv, const Options& options)
{
	assert(argc >= 1);
	int exitstatus = 66;

	// nany context
	nycontext_t ctx;
	bool init = initializeContext(ctx, options);
	if (YUNI_UNLIKELY(not init))
		return exitstatus;

	// sources
	String scriptfile;
	IO::Canonicalize(scriptfile, argv[0]);
	auto r = nany_source_add_from_file_n(&ctx, scriptfile.c_str(), scriptfile.size());
	init = (r == nytrue);

	// building
	bool buildstatus;
	if (init)
	{
		nyreport_t* report = nullptr;
		buildstatus = (nany_build(&ctx, &report) == nytrue);

		// report printing
		// if an error has occured or if in verbose mode
		if (YUNI_UNLIKELY((not buildstatus) or options.verbose))
			(buildstatus ? nany_report_print_stdout : nany_report_print_stderr)(report);

		nany_report_unref(&report);
	}
	else
		buildstatus = false;

	// executing the program
	if (buildstatus)
	{
		if (argc == 1)
		{
			const char* nargv[] = { scriptfile.c_str(), nullptr };
			exitstatus = nany_run_main(&ctx, 1, nargv);
		}
		else
		{
			auto** nargv = (const char**)::malloc(((size_t) argc + 1) * sizeof(const char**));
			if (nargv)
			{
				for (int i = 1; i < argc; ++i)
					nargv[i] = argv[i];
				nargv[0]    = scriptfile.c_str();
				nargv[argc] = nullptr;

				exitstatus = nany_run_main(&ctx, argc, nargv);
				free(nargv);
			}
		}
	}

	nany_uninitialize(&ctx);
	return exitstatus;
}

int main(int argc, char** argv)
{
	argv0 = argv[0];
	if (YUNI_UNLIKELY(argc <= 1))
	{
		std::cerr << argv0 << ": no input script file\n";
		return EXIT_FAILURE;
	}

	try
	{
		Options options;
		int firstarg = -1;
		for (int i = 1; i < argc; ++i)
		{
			const char* const carg = argv[i];
			if (carg[0] == '-')
			{
				if (carg[1] == '-')
				{
					if (carg[2] != '\0') // to handle '--' option
					{
						AnyString arg{carg};
						if (arg == "--help")
							return printUsage(argv[0]);
						if (arg == "--version")
							return printVersion();
						if (arg == "--bugreport")
							return printBugReportInfo();
						if (arg == "--verbose")
						{
							options.verbose = true;
							continue;
						}
						return unknownOption(arg);
					}
					else
					{
						firstarg = i + 1;
						break; // nothing must interpreted after '--'
					}
				}
				else
				{
					AnyString arg{carg};
					if (arg == "-h")
						return printUsage(argv[0]);
					if (arg == "-v")
						return printVersion();
					return unknownOption(arg);
				}
			}

			firstarg = i;
			break;
		}

		//
		// -- execute the script
		//
		return execute(argc - firstarg, argv + firstarg, options);
	}
	catch (std::bad_alloc&)
	{
		std::cerr << '\n' << argv0 << ": error: failed to allocate memory\n";
	}
	catch (...)
	{
		std::cerr << '\n' << argv0 << ": error: unhandled exception\n";
	}
	return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File: Tester.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Tester executable.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <TestData.h>
#include <Metric.h>

#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <boost/program_options.hpp>

using namespace std;
using namespace Nektar;

// Define some namespace aliases
namespace po = boost::program_options;
namespace fs = boost::filesystem;

string PortablePath(const boost::filesystem::path& path)
{
    boost::filesystem::path temp = path;
#if BOOST_VERSION > 104200
    temp.make_preferred();
    return temp.string();
#else
    return temp.file_string();
#endif
}

int main(int argc, char *argv[])
{
    int status = 0;
    string command;

    // Set up command line options.
    po::options_description desc("Available options");
    desc.add_options()
        ("help,h",                 "Produce this help message.")
        ("verbose,v",              "Turn on verbosity.")
        ("generate-metric,g",      po::value<vector<int> >(),
                                   "Generate a single metric.")
        ("generate-all-metrics,a", "Generate all metrics.");

    po::options_description hidden("Hidden options");
    hidden.add_options()
        ("input-file",   po::value<string>(), "Input filename");

    po::options_description cmdline_options;
    cmdline_options.add(hidden).add(desc);

    po::options_description visible("Allowed options");
    visible.add(desc);

    po::positional_options_description p;
    p.add("input-file", -1);

    po::variables_map vm;

    try
    {
        po::store(po::command_line_parser(argc, argv).
                  options(cmdline_options).positional(p).run(), vm);
        po::notify(vm);
    }
    catch (const exception& e)
    {
        cerr << e.what() << endl;
        cerr << desc;
        return 1;
    }

    if (vm.count("help") || vm.count("input-file") != 1) {
        cerr << "Usage: Tester [options] input-file.tst" << endl;
        cout << desc;
        return 1;
    }

    // Set up set containing metrics to be generated.
    vector<int> metricGenVec;
    if (vm.count("generate-metric"))
    {
        metricGenVec = vm["generate-metric"].as<vector<int> >();
        cout << "SIZE = " << metricGenVec.size() << endl;
    }
    set<int> metricGen(metricGenVec.begin(), metricGenVec.end());

    // Path to test definition file
    const fs::path specFile(vm["input-file"].as<string>());

    // Parent path of test definition file containing dependent files
    fs::path specPath = specFile.parent_path();

    if (specPath.empty())
    {
        specPath = fs::current_path();
    }

#if BOOST_VERSION > 104200
    string specFileStem = specFile.stem().string();
#else
    string specFileStem = specFile.stem().file_string();
#endif

    // Temporary directory to create and in which to conduct test
    const fs::path tmpDir = fs::current_path()
        / fs::path("tmp_" + specFileStem);

    // The current directory
    const fs::path startDir = fs::current_path();

    try
    {
        // Parse the test file
        TestData file(specFile);

        // Generate the metric objects
        vector<MetricSharedPtr> metrics;
        for (unsigned int i = 0; i < file.GetNumMetrics(); ++i)
        {
            set<int>::iterator it = metricGen.find(file.GetMetricId(i));
            bool genMetric = it != metricGen.end() ||
                             (vm.count("generate-all-metrics") > 0);

            metrics.push_back( GetMetricFactory().CreateInstance(
                                                    file.GetMetricType(i),
                                                    file.GetMetric(i),
                                                    genMetric
                                                  ));

            if (it != metricGen.end())
            {
                metricGen.erase(it);
            }
        }

        if (metricGen.size() != 0)
        {
            string s = metricGen.size() == 1 ? "s" : "";
            set<int>::iterator it;
            cerr << "Unable to find metric"+s+" with ID"+s+" ";
            for (it = metricGen.begin(); it != metricGen.end(); ++it)
            {
                cerr << *it << " ";
            }
            cerr << endl;
            return 1;
        }

        // Remove the temporary directory if left from a previous test
        if (fs::exists(tmpDir))
        {
            fs::remove_all(tmpDir);
        }

        // Create temporary directory
        fs::create_directory(tmpDir);

        // Change working directory to the temporary directory
        fs::current_path(tmpDir);

        // Copy required files for this test from the test definition directory
        // to the temporary directory.
        for (unsigned int i = 0; i < file.GetNumDependentFiles(); ++i)
        {
            fs::path source_file(file.GetDependentFile(i).m_filename);

            fs::path source = specPath / source_file;
            fs::path dest   = tmpDir   / source_file;
            fs::copy_file(source, dest);
        }

        // Construct test command to run. If in debug mode, append "-g"
        // Output from stdout and stderr are directed to the files output.out
        // and output.err, respectively.
        if (file.GetNProcesses() > 1)
        {
            command += "mpirun -np "
                    + boost::lexical_cast<string>(file.GetNProcesses())
                    + " ";
        }

        // If executable doesn't exist in path then hope that it is in the
        // user's PATH environment variable.
        fs::path execPath = startDir / fs::path(file.GetExecutable());
        if (!fs::exists(execPath))
        {
            execPath = fs::path(file.GetExecutable());
        }

        command += PortablePath(execPath);
        command += " ";
        command += file.GetParameters();
        command += " 1>output.out 2>output.err";

        // Run executable to perform test.
        if (system(command.c_str()))
        {
            cerr << "Error occurred running test:" << endl;
            cerr << "Command: " << command << endl;
            throw 1;
        }

        // Check output files exist
        if (!(fs::exists("output.out") && fs::exists("output.err")))
        {
            cerr << "One or more test output files are missing." << endl;
            throw 1;
        }

        // Open output files and check they are readable
        ifstream vStdout("output.out");
        ifstream vStderr("output.err");
        if (vStdout.bad() || vStderr.bad())
        {
            cerr << "One or more test output files are unreadable." << endl;
            throw 1;
        }

        // Test against all metrics
        status = 0;
        for (int i = 0; i < metrics.size(); ++i)
        {
            vStdout.clear();
            vStderr.clear();
            vStdout.seekg(0, ios::beg);
            vStderr.seekg(0, ios::beg);
            if (!metrics[i]->Test(vStdout, vStderr))
            {
                status = 1;
            }
        }

        // Change back to the original path and delete temporary directory
        fs::current_path(startDir);
        fs::remove_all(tmpDir);

        // Save any changes.
        if (vm.count("generate-metric")      > 0 ||
            vm.count("generate-all-metrics") > 0)
        {
            file.SaveFile();
        }

        // Return status of test. 0 = PASS, 1 = FAIL
        return status;
    }
    catch (const fs::filesystem_error& e)
    {
        cerr << "Filesystem operation error occurred:" << endl;
        cerr << "  " << e.what() << endl;
        cerr << "  Files left in " << tmpDir.string() << endl;
    }
    catch (...)
    {
        cerr << "  Files left in " << tmpDir.string() << endl;
    }

    // If a system error, return 2
    return 2;
}
<commit_msg>Another fix for boost less than 1.42.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File: Tester.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Tester executable.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <TestData.h>
#include <Metric.h>

#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <boost/program_options.hpp>

using namespace std;
using namespace Nektar;

// Define some namespace aliases
namespace po = boost::program_options;
namespace fs = boost::filesystem;

string PortablePath(const boost::filesystem::path& path)
{
    boost::filesystem::path temp = path;
#if BOOST_VERSION > 104200
    temp.make_preferred();
    return temp.string();
#else
    return temp.file_string();
#endif
}

int main(int argc, char *argv[])
{
    int status = 0;
    string command;

    // Set up command line options.
    po::options_description desc("Available options");
    desc.add_options()
        ("help,h",                 "Produce this help message.")
        ("verbose,v",              "Turn on verbosity.")
        ("generate-metric,g",      po::value<vector<int> >(),
                                   "Generate a single metric.")
        ("generate-all-metrics,a", "Generate all metrics.");

    po::options_description hidden("Hidden options");
    hidden.add_options()
        ("input-file",   po::value<string>(), "Input filename");

    po::options_description cmdline_options;
    cmdline_options.add(hidden).add(desc);

    po::options_description visible("Allowed options");
    visible.add(desc);

    po::positional_options_description p;
    p.add("input-file", -1);

    po::variables_map vm;

    try
    {
        po::store(po::command_line_parser(argc, argv).
                  options(cmdline_options).positional(p).run(), vm);
        po::notify(vm);
    }
    catch (const exception& e)
    {
        cerr << e.what() << endl;
        cerr << desc;
        return 1;
    }

    if (vm.count("help") || vm.count("input-file") != 1) {
        cerr << "Usage: Tester [options] input-file.tst" << endl;
        cout << desc;
        return 1;
    }

    // Set up set containing metrics to be generated.
    vector<int> metricGenVec;
    if (vm.count("generate-metric"))
    {
        metricGenVec = vm["generate-metric"].as<vector<int> >();
        cout << "SIZE = " << metricGenVec.size() << endl;
    }
    set<int> metricGen(metricGenVec.begin(), metricGenVec.end());

    // Path to test definition file
    const fs::path specFile(vm["input-file"].as<string>());

    // Parent path of test definition file containing dependent files
    fs::path specPath = specFile.parent_path();

    if (specPath.empty())
    {
        specPath = fs::current_path();
    }

#if BOOST_VERSION > 104200
    string specFileStem = specFile.stem().string();
#else
    string specFileStem = specFile.stem();
#endif

    // Temporary directory to create and in which to conduct test
    const fs::path tmpDir = fs::current_path()
        / fs::path("tmp_" + specFileStem);

    // The current directory
    const fs::path startDir = fs::current_path();

    try
    {
        // Parse the test file
        TestData file(specFile);

        // Generate the metric objects
        vector<MetricSharedPtr> metrics;
        for (unsigned int i = 0; i < file.GetNumMetrics(); ++i)
        {
            set<int>::iterator it = metricGen.find(file.GetMetricId(i));
            bool genMetric = it != metricGen.end() ||
                             (vm.count("generate-all-metrics") > 0);

            metrics.push_back( GetMetricFactory().CreateInstance(
                                                    file.GetMetricType(i),
                                                    file.GetMetric(i),
                                                    genMetric
                                                  ));

            if (it != metricGen.end())
            {
                metricGen.erase(it);
            }
        }

        if (metricGen.size() != 0)
        {
            string s = metricGen.size() == 1 ? "s" : "";
            set<int>::iterator it;
            cerr << "Unable to find metric"+s+" with ID"+s+" ";
            for (it = metricGen.begin(); it != metricGen.end(); ++it)
            {
                cerr << *it << " ";
            }
            cerr << endl;
            return 1;
        }

        // Remove the temporary directory if left from a previous test
        if (fs::exists(tmpDir))
        {
            fs::remove_all(tmpDir);
        }

        // Create temporary directory
        fs::create_directory(tmpDir);

        // Change working directory to the temporary directory
        fs::current_path(tmpDir);

        // Copy required files for this test from the test definition directory
        // to the temporary directory.
        for (unsigned int i = 0; i < file.GetNumDependentFiles(); ++i)
        {
            fs::path source_file(file.GetDependentFile(i).m_filename);

            fs::path source = specPath / source_file;
            fs::path dest   = tmpDir   / source_file;
            fs::copy_file(source, dest);
        }

        // Construct test command to run. If in debug mode, append "-g"
        // Output from stdout and stderr are directed to the files output.out
        // and output.err, respectively.
        if (file.GetNProcesses() > 1)
        {
            command += "mpirun -np "
                    + boost::lexical_cast<string>(file.GetNProcesses())
                    + " ";
        }

        // If executable doesn't exist in path then hope that it is in the
        // user's PATH environment variable.
        fs::path execPath = startDir / fs::path(file.GetExecutable());
        if (!fs::exists(execPath))
        {
            execPath = fs::path(file.GetExecutable());
        }

        command += PortablePath(execPath);
        command += " ";
        command += file.GetParameters();
        command += " 1>output.out 2>output.err";

        // Run executable to perform test.
        if (system(command.c_str()))
        {
            cerr << "Error occurred running test:" << endl;
            cerr << "Command: " << command << endl;
            throw 1;
        }

        // Check output files exist
        if (!(fs::exists("output.out") && fs::exists("output.err")))
        {
            cerr << "One or more test output files are missing." << endl;
            throw 1;
        }

        // Open output files and check they are readable
        ifstream vStdout("output.out");
        ifstream vStderr("output.err");
        if (vStdout.bad() || vStderr.bad())
        {
            cerr << "One or more test output files are unreadable." << endl;
            throw 1;
        }

        // Test against all metrics
        status = 0;
        for (int i = 0; i < metrics.size(); ++i)
        {
            vStdout.clear();
            vStderr.clear();
            vStdout.seekg(0, ios::beg);
            vStderr.seekg(0, ios::beg);
            if (!metrics[i]->Test(vStdout, vStderr))
            {
                status = 1;
            }
        }

        // Change back to the original path and delete temporary directory
        fs::current_path(startDir);
        fs::remove_all(tmpDir);

        // Save any changes.
        if (vm.count("generate-metric")      > 0 ||
            vm.count("generate-all-metrics") > 0)
        {
            file.SaveFile();
        }

        // Return status of test. 0 = PASS, 1 = FAIL
        return status;
    }
    catch (const fs::filesystem_error& e)
    {
        cerr << "Filesystem operation error occurred:" << endl;
        cerr << "  " << e.what() << endl;
        cerr << "  Files left in " << tmpDir.string() << endl;
    }
    catch (...)
    {
        cerr << "  Files left in " << tmpDir.string() << endl;
    }

    // If a system error, return 2
    return 2;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Luke San Antonio
 * All rights reserved.
 */
#include <chrono>
#include "sdl_helper.h"
#include "gfx/scene.h"
#include "assets/minigltf.h"
#include "common/log.h"
int main(int argc, char** argv)
{
  redc::Scoped_Log_Init log_raii{};
  if(argc < 2)
  {
    redc::log_e("usage: % <filename.gltf>", argv[0]);
    return EXIT_FAILURE;
  }

  auto sdl_init = init_sdl("glTF viewer", redc::Vec<int>{1000, 1000}, false,
                           false);

  auto before = std::chrono::high_resolution_clock::now();
  auto desc = redc::load_gltf_file(argv[1]);
  auto asset = redc::load_asset(desc.value());
  auto after = std::chrono::high_resolution_clock::now();

  auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
  redc::log_i("Took %s to load", dt.count() / 1000.0);

  return EXIT_SUCCESS;
}
<commit_msg>Print information about loaded asset hierarchy<commit_after>/*
 * Copyright (C) 2016 Luke San Antonio
 * All rights reserved.
 */
#include <chrono>
#include <string>
#include "sdl_helper.h"
#include "gfx/scene.h"
#include "assets/minigltf.h"
#include "common/log.h"
int main(int argc, char** argv)
{
  redc::Scoped_Log_Init log_raii{};
  if(argc < 2)
  {
    redc::log_e("usage: % <filename.gltf>", argv[0]);
    return EXIT_FAILURE;
  }

  auto sdl_init = init_sdl("glTF viewer", redc::Vec<int>{1000, 1000}, false,
                           false);

  auto before = std::chrono::high_resolution_clock::now();
  auto desc = redc::load_gltf_file(argv[1]);
  auto asset = redc::load_asset(desc.value());
  auto after = std::chrono::high_resolution_clock::now();

  auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
  redc::log_i("Took %s to load", dt.count() / 1000.0);

  // List materials, shaders, programs and techniques
  for(auto mat_pair : desc->materials)
  {
    redc::log_i("Material: %", mat_pair.first);
    redc::log_i("\tname: %", mat_pair.second.name);
    redc::log_i("\ttechnique: %", mat_pair.second.technique);
    for(auto param_pair : mat_pair.second.values)
    {
      redc::log_i("\tParameter: %", param_pair.first);
      redc::log_i("\t\tstring_value: %", param_pair.second.string_value);
      std::string number_array = "[";
      for(auto num : param_pair.second.number_array)
      {
        number_array += std::to_string(num) + ", ";
      }
      number_array += "]";
      redc::log_i("\t\tnumber_array: %", number_array);
    }
  }
  for(auto mesh_pair : desc->meshes)
  {
    redc::log_i("Mesh: %", mesh_pair.first);
    std::size_t i = 0;
    for(auto prim : mesh_pair.second.primitives)
    {
      redc::log_i("\t% material: %", i, prim.material);
      redc::log_i("\t% indices: %", i, prim.indices);
      redc::log_i("\t% mode: %", i, prim.mode);
      for(auto attrib_pair : prim.attributes)
      {
        redc::log_i("\t%\tattribute %:%", i, attrib_pair.first,
                    attrib_pair.second);
      }
      ++i;
    }
  }
  for(auto shader_pair : desc->shaders)
  {
    redc::log_i("Shader: %", shader_pair.first);
    redc::log_i("\tname: %", shader_pair.second.name);
    redc::log_i("\ttype: %", shader_pair.second.type);

    std::string source(shader_pair.second.source.begin(),
                       shader_pair.second.source.end());
    redc::log_i("\tsource:\n%", source);
  }
  for(auto program_pair : desc->programs)
  {
    redc::log_i("Program: %", program_pair.first);
    redc::log_i("\tvertexShader: %", program_pair.second.vertexShader);
    redc::log_i("\tfragmentShader: %", program_pair.second.fragmentShader);
    for(auto attrib : program_pair.second.attributes)
    {
      redc::log_i("\tattribute %", attrib);
    }
  }
  for(auto technique_pair : desc->techniques)
  {
    redc::log_i("Technique: %", technique_pair.first);
    redc::log_i("\tname: %", technique_pair.second.name);
    redc::log_i("\tprogram: %", technique_pair.second.program);

    for(auto attrib_pair : technique_pair.second.attributes)
    {
      redc::log_i("\tattribute %:%", attrib_pair.first, attrib_pair.second);
    }
    for(auto uniform_pair : technique_pair.second.uniforms)
    {
      redc::log_i("\tuniform %:%", uniform_pair.first, uniform_pair.second);
    }
    for(auto parameter_pair : technique_pair.second.parameters)
    {
      redc::log_i("\tParameter: %", parameter_pair.first);
      redc::log_i("\t\tcount: %", parameter_pair.second.count);
      redc::log_i("\t\tnode: %", parameter_pair.second.node);
      redc::log_i("\t\ttype: %", parameter_pair.second.type);
      redc::log_i("\t\tsemantic: %", parameter_pair.second.semantic);
      redc::log_i("\t\tValue:");
      redc::log_i("\t\t\tstring_value: %",
                  parameter_pair.second.value.string_value);
      std::string number_array = "[";
      for(auto num : parameter_pair.second.value.number_array)
      {
        number_array += std::to_string(num) + ", ";
      }
      number_array += "]";
      redc::log_i("\t\t\tnumber_array: %", number_array);

    }
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "locations.h"

#include <iostream>
#include <sstream>
#include <stdexcept>

#include "util.h"

size_t read_locations(std::ifstream& file, BPTree<Location>& tree) {
    using namespace std;
    size_t locations_read = 0;
    while(1) {
        string line;
        getline(file, line);
        if (file.eof()) {
            break;
        }
        Location loc;
        stringstream line_stream(line);
        string s;
        getline(line_stream, s, '|');
        try {
            loc.id = stou_safe(s);
        } catch (logic_error& e) {
            continue;
        }
        getline(line_stream, s);
        if (!s.empty()) {
            size_t length = s.copy(loc.name, 127);
            loc.name[length] = 0;
            tree.insert((int32_t)loc.id, loc);
            locations_read++;
        }
    }
    return locations_read;
}

ModeInfo adjModeInfo = {
    // init_mode
    [] (std::ifstream& file, ModeData& data) {
        using namespace std;
        cout << "reading edges... ";
        cout.flush();
        size_t edges_read = 0;
        BPTree<AdjacentLocation> edges;
        while (1) {
            string line;
            getline(file, line);
            if (file.eof()) {
                break;
            }
            AdjacentLocation edge;
            stringstream line_stream(line);
            try {
                string s;
                getline(line_stream, s, '|');
                edge.parent_id = stou_safe(s);
                getline(line_stream, s, '|');
                edge.child_id = stou_safe(s);
            } catch (logic_error& e) {
                continue;
            }
            edges.insert((int32_t)edge.parent_id, edge);
            edges_read++;
        }
        data.adj.edges = edges;
        cout << "got " << edges_read << endl;
        return 0;
    },
    // run_input
    [] (BPTree<Location>& locs, ModeData& data, std::string& input) {
        using namespace std;
        stringstream stream(input);
        string s;
        stream >> s;
        if (s == "search") {
            uint32_t loc_id;
            stream >> s;
            try {
                loc_id = stou_safe(s);
            } catch (logic_error& e) {
                cout << "invalid id" << endl;
                return 0;
            }
            cout << "searching id " << loc_id << ": ";
            cout.flush();
            Location loc;
            if (locs.search((int32_t)loc_id, loc)) {
                cout << "found \"" << loc.name << '"' << endl;
            } else {
                cout << "not found" << endl;
            }
        } else {
            cout << "unknown command '" << s << "'" << endl;
        }
        return 0;
    },
    nullptr
};

ModeInfo niModeInfo = {
    nullptr,
    nullptr,
    nullptr
};

ModeInfo deltaniModeInfo = {
    nullptr,
    nullptr,
    nullptr
};
<commit_msg>Added num_childs child_ids and is_ancestor commands<commit_after>#include "locations.h"

#include <iostream>
#include <stack>
#include <sstream>
#include <stdexcept>

#include "util.h"

size_t read_locations(std::ifstream& file, BPTree<Location>& tree) {
    using namespace std;
    size_t locations_read = 0;
    while(1) {
        string line;
        getline(file, line);
        if (file.eof()) {
            break;
        }
        Location loc;
        stringstream line_stream(line);
        string s;
        getline(line_stream, s, '|');
        try {
            loc.id = stou_safe(s);
        } catch (logic_error& e) {
            continue;
        }
        getline(line_stream, s);
        if (!s.empty()) {
            size_t length = s.copy(loc.name, 127);
            loc.name[length] = 0;
            tree.insert((int32_t)loc.id, loc);
            locations_read++;
        }
    }
    return locations_read;
}

ModeInfo adjModeInfo = {
    // init_mode
    [] (std::ifstream& file, ModeData& data) {
        using namespace std;
        cout << "reading edges... ";
        cout.flush();
        size_t edges_read = 0;
        BPTree<AdjacentLocation> edges;
        while (1) {
            string line;
            getline(file, line);
            if (file.eof()) {
                break;
            }
            AdjacentLocation edge;
            stringstream line_stream(line);
            try {
                string s;
                getline(line_stream, s, '|');
                edge.parent_id = stou_safe(s);
                getline(line_stream, s, '|');
                edge.child_id = stou_safe(s);
            } catch (logic_error& e) {
                continue;
            }
            edges.insert((int32_t)edge.parent_id, edge);
            edges_read++;
        }
        data.adj.edges = edges;
        cout << "got " << edges_read << endl;
        return 0;
    },
    // run_input
    [] (BPTree<Location>& locs, ModeData& data, std::string& input) {
        using namespace std;
        stringstream stream(input);
        string s;
        stream >> s;
        if (s == "search") {
            uint32_t loc_id;
            stream >> s;
            try {
                loc_id = stou_safe(s);
            } catch (logic_error& e) {
                cout << "invalid id" << endl;
                return 0;
            }
            cout << "searching id " << loc_id << ": ";
            cout.flush();
            Location loc;
            if (locs.search((int32_t)loc_id, loc)) {
                cout << "found \"" << loc.name << '"' << endl;
            } else {
                cout << "not found" << endl;
            }
        } else if (s == "num_childs") {
            uint32_t parent_id;
            try {
                stream >> s;
                parent_id = stou_safe(s);
            } catch (logic_error& e) {
                cout << "invalid id" << endl;
                return 0;
            }
            cout << "number of childs: " << data.adj.edges.count_key(parent_id) << endl;
        } else if (s == "child_ids") {
            uint32_t parent_id;
            try {
                stream >> s;
                parent_id = stou_safe(s);
            } catch (logic_error& e) {
                cout << "invalid id" << endl;
                return 0;
            }
            cout << "child ids: " << endl;
            for (AdjacentLocation& edge : data.adj.edges.search_iter(parent_id)) {
                cout << edge.child_id << endl;
            }
        } else if (s == "is_ancestor") {
            uint32_t parent_id;
            uint32_t child_id;
            try {
                stream >> s;
                parent_id = stou_safe(s);
                stream >> s;
                child_id = stou_safe(s);
            } catch (logic_error& e) {
                cout << "invalid ids" << endl;
                return 0;
            }
            stack<uint32_t> search_ids;
            search_ids.push(parent_id);
            while (!search_ids.empty()) {
                uint32_t search_id = search_ids.top();
                search_ids.pop();
                for (AdjacentLocation& edge : data.adj.edges.search_iter(search_id)) {
                    if (edge.child_id == child_id) {
                        goto is_ancestor;
                    }
                    search_ids.push(edge.child_id);
                }
            }
            cout << "id " << parent_id << " is NOT an ancestor of id " << child_id << endl;
            return 0;
            is_ancestor:
            cout << "id " << parent_id << " is an ancestor of id " << child_id << endl;
        } else {
            cout << "unknown command '" << s << "'" << endl;
        }
        return 0;
    },
    nullptr
};

ModeInfo niModeInfo = {
    nullptr,
    nullptr,
    nullptr
};

ModeInfo deltaniModeInfo = {
    nullptr,
    nullptr,
    nullptr
};
<|endoftext|>


<commit_before>#ifndef POWERSET_HPP_
#define POWERSET_HPP_

#include "iterbase.hpp"
#include "combinations.hpp"
#include "enumerate.hpp"

#include <cassert>
#include <vector>
#include <initializer_list>
#include <utility>
#include <iterator>

namespace iter {
    template <typename Container,
              typename CombinatorType=
                  decltype(combinations(std::declval<Container&>(), 0))>
    class Powersetter {
        private:
            Container container;

            std::vector<CombinatorType> combinators;
        public:
            Powersetter(Container in_container)
                : container(std::forward<Container>(in_container))
            {
                combinators.push_back(combinations(this->container, 0));
                std::size_t i = 1;
                for (auto iter = std::begin(this->container),
                            end = std::end(this->container);
                        iter != end;
                        ++iter, ++i) {
                    combinators.push_back(combinations(this->container, i));
                }
            }

            class Iterator
                : public std::iterator<
                      std::input_iterator_tag, iterator_deref<CombinatorType>>
            {
                private:
                    std::size_t container_size;
                    std::size_t list_size = 0;
                    bool not_done = true;

                    std::vector<CombinatorType>& combinators;
                    std::vector<iterator_type<CombinatorType>> inner_iters;
                public:
                    Iterator(std::vector<CombinatorType>& combs)
                        : container_size{combs.size() - 1},
                        combinators(combs)
                    {
                        for (auto& comb : combinators) {
                            inner_iters.push_back(std::begin(comb));
                        }
                    }

                    Iterator& operator++() {
                        ++inner_iters[list_size];
                        if (!(inner_iters[list_size] != inner_iters[list_size])) {
                            ++list_size;
                        }
                        if (container_size < list_size) {
                            not_done = false;
                        }

                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    iterator_deref<CombinatorType> operator*() {
                        return *(inner_iters[list_size]);
                    }

                    bool operator != (const Iterator&) {
                        return not_done;
                    }
            };

            Iterator begin() {
                return {this->combinators};
            }

            Iterator end() {
                return {this->combinators};
            }
    };

    template <typename Container>
    Powersetter<Container> powerset(Container&& container) {
        return {std::forward<Container>(container)};
    }

    template <typename T>
    Powersetter<std::initializer_list<T>> powerset(
            std::initializer_list<T> il) {
        return {il};
    }
}
#endif // #ifndef POWERSET_HPP_
<commit_msg>adds powerset iter ==<commit_after>#ifndef POWERSET_HPP_
#define POWERSET_HPP_

#include "iterbase.hpp"
#include "combinations.hpp"
#include "enumerate.hpp"

#include <cassert>
#include <vector>
#include <initializer_list>
#include <utility>
#include <iterator>

namespace iter {
    template <typename Container,
              typename CombinatorType=
                  decltype(combinations(std::declval<Container&>(), 0))>
    class Powersetter {
        private:
            Container container;

            std::vector<CombinatorType> combinators;
        public:
            Powersetter(Container in_container)
                : container(std::forward<Container>(in_container))
            {
                combinators.push_back(combinations(this->container, 0));
                std::size_t i = 1;
                for (auto iter = std::begin(this->container),
                            end = std::end(this->container);
                        iter != end;
                        ++iter, ++i) {
                    combinators.push_back(combinations(this->container, i));
                }
            }

            class Iterator
                : public std::iterator<
                      std::input_iterator_tag, iterator_deref<CombinatorType>>
            {
                private:
                    std::size_t container_size;
                    std::size_t list_size = 0;
                    bool not_done = true;

                    std::vector<CombinatorType>& combinators;
                    std::vector<iterator_type<CombinatorType>> inner_iters;
                public:
                    Iterator(std::vector<CombinatorType>& combs)
                        : container_size{combs.size() - 1},
                        combinators(combs)
                    {
                        for (auto& comb : combinators) {
                            inner_iters.push_back(std::begin(comb));
                        }
                    }

                    Iterator& operator++() {
                        ++inner_iters[list_size];
                        if (!(inner_iters[list_size] != inner_iters[list_size])) {
                            ++list_size;
                        }
                        if (container_size < list_size) {
                            not_done = false;
                        }

                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    iterator_deref<CombinatorType> operator*() {
                        return *(inner_iters[list_size]);
                    }

                    bool operator != (const Iterator&) {
                        return not_done;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() {
                return {this->combinators};
            }

            Iterator end() {
                return {this->combinators};
            }
    };

    template <typename Container>
    Powersetter<Container> powerset(Container&& container) {
        return {std::forward<Container>(container)};
    }

    template <typename T>
    Powersetter<std::initializer_list<T>> powerset(
            std::initializer_list<T> il) {
        return {il};
    }
}
#endif // #ifndef POWERSET_HPP_
<|endoftext|>


<commit_before>/*
* Written by David A. Burgess, Kestrel Signal Processing, Inc., 2010
* The author disclaims copyright to this source code.
*/

#include "sqlite3.h"
#include "sqlite3util.h"

#include <string.h>
#include <unistd.h>
#include <stdio.h>

// Wrappers to sqlite operations.
// These will eventually get moved to commonlibs.

int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query)
{
	int prc = sqlite3_prepare_v2(DB,query,strlen(query),stmt,NULL);
	if (prc) {
		fprintf(stderr,"sqlite3_prepare_v2 failed for \"%s\": %s\n",query,sqlite3_errmsg(DB));
		sqlite3_finalize(*stmt);
	}
	return prc;
}

int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt)
{
	int src = SQLITE_BUSY;
	while (src==SQLITE_BUSY) {
		src = sqlite3_step(stmt);
		if (src==SQLITE_BUSY) {
			usleep(100000);
		}
	}
	if ((src!=SQLITE_DONE) && (src!=SQLITE_ROW)) {
		fprintf(stderr,"sqlite3_run_query failed: %s: %s\n", sqlite3_sql(stmt), sqlite3_errmsg(DB));
	}
	return src;
}

bool sqlite3_exists(sqlite3* DB, const char *tableName,
		const char* keyName, const char* keyData)
{
	size_t stringSize = 100 + strlen(tableName) + strlen(keyName) + strlen(keyData);
	char query[stringSize];
	sprintf(query,"SELECT * FROM %s WHERE %s == \"%s\"",tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	sqlite3_finalize(stmt);
	// Anything there?
	return (src == SQLITE_ROW);
}

bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
		const char* keyName, const char* keyData,
		const char* valueName, unsigned &valueData)
{
	size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
	char query[stringSize];
	sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	bool retVal = false;
	if (src == SQLITE_ROW) {
		valueData = (unsigned)sqlite3_column_int64(stmt,0);
		retVal = true;
	}
	sqlite3_finalize(stmt);
	return retVal;
}

// This function returns an allocated string that must be free'd by the caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
		const char* keyName, const char* keyData,
		const char* valueName, char* &valueData)
{
	valueData=NULL;
	size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
	char query[stringSize];
	sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	bool retVal = false;
	if (src == SQLITE_ROW) {
		const char* ptr = (const char*)sqlite3_column_text(stmt,0);
		if (ptr) valueData = strdup(ptr);
		retVal = true;
	}
	sqlite3_finalize(stmt);
	return retVal;
}

// This function returns an allocated string that must be free'd by tha caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
		const char* keyName, unsigned keyData,
		const char* valueName, char* &valueData)
{
	valueData=NULL;
	size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + 20;
	char query[stringSize];
	sprintf(query,"SELECT %s FROM %s WHERE %s == %u",valueName,tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	bool retVal = false;
	if (src == SQLITE_ROW) {
		const char* ptr = (const char*)sqlite3_column_text(stmt,0);
		if (ptr) valueData = strdup(ptr);
		retVal = true;
	}
	sqlite3_finalize(stmt);
	return retVal;
}

bool sqlite3_command(sqlite3* DB, const char* query)
{
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Run the query.
	int src = sqlite3_run_query(DB,stmt);
	return src==SQLITE_DONE;
}

<commit_msg>Synced sqlite3utils with private and fixed a small recursive bug in SIPEngine that was already fixed in private<commit_after>/*
* Copyright 2010 Kestrel Signal Processing, Inc.
* All rights reserved.
*/

#include "sqlite3.h"
#include "sqlite3util.h"

#include <string.h>
#include <unistd.h>
#include <stdio.h>

// Wrappers to sqlite operations.
// These will eventually get moved to commonlibs.

int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query)
{
        int src = SQLITE_BUSY;
        while (src==SQLITE_BUSY) {
                src = sqlite3_prepare_v2(DB,query,strlen(query),stmt,NULL);
                if (src==SQLITE_BUSY) {
                        usleep(100000);
                }
        }
        if (src) {
                fprintf(stderr,"sqlite3_prepare_v2 failed for \"%s\": %s\n",query,sqlite3_errmsg(DB));
                sqlite3_finalize(*stmt);
        }
        return src;
}

int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt)
{
	int src = SQLITE_BUSY;
	while (src==SQLITE_BUSY) {
		src = sqlite3_step(stmt);
		if (src==SQLITE_BUSY) {
			usleep(100000);
		}
	}
	if ((src!=SQLITE_DONE) && (src!=SQLITE_ROW)) {
		fprintf(stderr,"sqlite3_run_query failed: %s: %s\n", sqlite3_sql(stmt), sqlite3_errmsg(DB));
	}
	return src;
}

bool sqlite3_exists(sqlite3* DB, const char *tableName,
		const char* keyName, const char* keyData)
{
	size_t stringSize = 100 + strlen(tableName) + strlen(keyName) + strlen(keyData);
	char query[stringSize];
	sprintf(query,"SELECT * FROM %s WHERE %s == \"%s\"",tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	sqlite3_finalize(stmt);
	// Anything there?
	return (src == SQLITE_ROW);
}

bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
		const char* keyName, const char* keyData,
		const char* valueName, unsigned &valueData)
{
	size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
	char query[stringSize];
	sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	bool retVal = false;
	if (src == SQLITE_ROW) {
		valueData = (unsigned)sqlite3_column_int64(stmt,0);
		retVal = true;
	}
	sqlite3_finalize(stmt);
	return retVal;
}

// This function returns an allocated string that must be free'd by the caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
		const char* keyName, const char* keyData,
		const char* valueName, char* &valueData)
{
	valueData=NULL;
	size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
	char query[stringSize];
	sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	bool retVal = false;
	if (src == SQLITE_ROW) {
		const char* ptr = (const char*)sqlite3_column_text(stmt,0);
		if (ptr) valueData = strdup(ptr);
		retVal = true;
	}
	sqlite3_finalize(stmt);
	return retVal;
}

// This function returns an allocated string that must be free'd by tha caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
		const char* keyName, unsigned keyData,
		const char* valueName, char* &valueData)
{
	valueData=NULL;
	size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + 20;
	char query[stringSize];
	sprintf(query,"SELECT %s FROM %s WHERE %s == %u",valueName,tableName,keyName,keyData);
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Read the result.
	int src = sqlite3_run_query(DB,stmt);
	bool retVal = false;
	if (src == SQLITE_ROW) {
		const char* ptr = (const char*)sqlite3_column_text(stmt,0);
		if (ptr) valueData = strdup(ptr);
		retVal = true;
	}
	sqlite3_finalize(stmt);
	return retVal;
}

bool sqlite3_command(sqlite3* DB, const char* query)
{
	// Prepare the statement.
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
	// Run the query.
	int src = sqlite3_run_query(DB,stmt);
	sqlite3_finalize(stmt);
	return src==SQLITE_DONE;
}

<|endoftext|>


<commit_before>/*
 The MIT License (MIT)

 Copyright (c) 2014 Baptiste Burles, Kliplab

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <Arduino.h>
#include "../klipframework.h"

Queue::Queue(uint8_t * pBuffer, uint16_t size)
{
    reset();
    mSize = size;
    mPending = pBuffer;
}

void Queue::reset()
{
    mHead = 0;
    mTail = 0;
}

int Queue::available()
{
    if (mHead == mTail)
    {
        return 0;
    }

    if (mHead <= mTail)
    {
        return mTail - mHead;
    }

    return (mSize - mTail + mHead);
}

bool Queue::write(uint8_t data)
{
    uint32_t size = mSize-1;
    if ( ((mTail+1) & (size)) == ((mHead) & (size)) )
    {
        return false;
    }

    mPending[mTail & (size)] = data;
    mTail++;

    return true;
}

bool Queue::read(uint8_t * data)
{
    if (mHead == mTail)
    {
        return false;
    }

    *data = mPending[mHead & (mSize-1)];
    mHead++;

    return true;
}
<commit_msg>Fix integer<commit_after>/*
 The MIT License (MIT)

 Copyright (c) 2014 Baptiste Burles, Kliplab

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <Arduino.h>
#include "../klipframework.h"

Queue::Queue(uint8_t * pBuffer, uint16_t size)
{
    reset();
    mSize = size;
    mPending = pBuffer;
}

void Queue::reset()
{
    mHead = 0;
    mTail = 0;
}

int Queue::available()
{
    if (mHead == mTail)
    {
        return 0;
    }

    if (mHead <= mTail)
    {
        return mTail - mHead;
    }

    return (mSize - mTail + mHead);
}

bool Queue::write(uint8_t data)
{
    uint16_t size = mSize-1;
    if ( ((mTail+1) & (size)) == ((mHead) & (size)) )
    {
        return false;
    }

    mPending[mTail & (size)] = data;
    mTail++;

    return true;
}

bool Queue::read(uint8_t * data)
{
    if (mHead == mTail)
    {
        return false;
    }

    *data = mPending[mHead & (mSize-1)];
    mHead++;

    return true;
}
<|endoftext|>


<commit_before>#include "AConfig.h"
#if(HAS_STD_CAMERAMOUNT)
#include <Servo.h>
#include "Device.h"
#include "Pin.h"
#include "CameraMount.h"
#include "Settings.h"

Servo tilt;
int tilt_val;
int new_tilt;

int smoothAdjustedCameraPosition(int target, int current){
  // if the MIDPOINT is betwen the change requested in velocity we want to go to MIDPOINT first, and right away.
  if (((current < MIDPOINT) && (MIDPOINT < target)) || ((target < MIDPOINT) && (MIDPOINT < current))){
    return MIDPOINT;
  }
  // if the change is moving us closer to MIDPOINT it is a reduction of power and we can move all the way to the target
  // in one command
  if (abs(MIDPOINT-target) < abs(MIDPOINT-current)){
    return target;
  }
  // else, we need to smooth out amp spikes by making a series of incrimental changes in the motors, so only move part of
  // the way to the target this time.
  double x = target - current;
  int sign = (x>0) - (x<0);
  int adjustedVal = current + sign * (min(abs(target - current), Settings::smoothingIncriment));
  // skip the deadzone
  if (sign<0) {
    return (min(adjustedVal,Settings::deadZone_min));
  } else if(sign>0){
    return (max(adjustedVal,Settings::deadZone_max));
  } else
    return (adjustedVal);
}

void CameraMount::device_setup(){
    tilt.attach(CAMERAMOUNT_PIN);
    Settings::capability_bitarray |= (1 << CAMERA_MOUNT_1_AXIS_CAPABLE);
}

void CameraMount::device_loop(Command command){
    if (command.cmp("tilt")) {
      tilt_val = command.args[1];
    }
    if (tilt_val != new_tilt){
      new_tilt = smoothAdjustedCameraPosition(tilt_val,new_tilt);
      tilt.writeMicroseconds(new_tilt);
    }
}

//void Cape::do_event(Event event){
//}
#endif

<commit_msg>Made smoothing along Camera Mount smooth in both directions<commit_after>#include "AConfig.h"
#if(HAS_STD_CAMERAMOUNT)
#include <Servo.h>
#include "Device.h"
#include "Pin.h"
#include "CameraMount.h"
#include "Settings.h"

Servo tilt;
int tilt_val;
int new_tilt;
const int tiltrate = 10;

int smoothAdjustedCameraPosition(int target, int current){
  // if the MIDPOINT is betwen the change requested in velocity we want to go to MIDPOINT first, and right away.
  if (((current < MIDPOINT) && (MIDPOINT < target)) || ((target < MIDPOINT) && (MIDPOINT < current))){
    return MIDPOINT;
  }

  // else, we need to smooth out amp spikes by making a series of incrimental changes in the motors, so only move part of
  // the way to the target this time.
  double x = target - current;
  int sign = (x>0) - (x<0);
  int adjustedVal = current + sign * (min(abs(target - current), tiltrate));
  // skip the deadzone
  if (sign<0) {
    return (min(adjustedVal,Settings::deadZone_min));
  } else if(sign>0){
    return (max(adjustedVal,Settings::deadZone_max));
  } else
    return (adjustedVal);
}

void CameraMount::device_setup(){
    tilt.attach(CAMERAMOUNT_PIN);
    Settings::capability_bitarray |= (1 << CAMERA_MOUNT_1_AXIS_CAPABLE);
}

void CameraMount::device_loop(Command command){
    if (command.cmp("tilt")) {
      tilt_val = command.args[1];
    }
    if (tilt_val != new_tilt){
      new_tilt = smoothAdjustedCameraPosition(tilt_val,new_tilt);
      tilt.writeMicroseconds(new_tilt);
    }
}

//void Cape::do_event(Event event){
//}
#endif

<|endoftext|>