/**
* @file
* @brief Line-of-sight algorithm.
*
*
*
* == Definition of visibility ==
*
* Two cells are in view of each other if there is any straight
* line that meets both cells and that doesn't meet any opaque
* cell in between, and if the cells are in LOS range of each
* other.
*
* Here, to "meet" a cell means to intersect the interior. In
* particular, rays can pass between to diagonally adjacent
* walls (as can the player).
*
* == Terminology ==
*
* A _ray_ is a line, specified by starting point (accx, accy)
* and slope. A ray determines its _footprint_: the sequence of
* cells whose interiour it meets.
*
* Any prefix of the footprint of a ray is called a _cellray_.
*
* For the purposes of LOS calculation, only the footprints
* are relevant, but rays are also used for shooting beams,
* which may travel beyond LOS and which can be reflected.
* See ray.cc.
*
* == Overview ==
*
* At first use, the LOS code makes some precomputations,
* filling a list of all relevant rays in one quadrant,
* and filling data structures that allow calculating LOS
* in a quadrant without checking each ray.
*
* The code provides functions for filling LOS information
* around a given center efficiently, and for querying rays
* between two given cells.
**/
#include "AppHdr.h"
#include "los.h"
#include <algorithm>
#include <cmath>
#include "areas.h"
#include "coord.h"
#include "coordit.h"
#include "env.h"
#include "losglobal.h"
#include "mon-act.h"
// These determine what rays are cast in the precomputation,
// and affect start-up time significantly.
// XXX: Argue that these values are sufficient.
#define LOS_MAX_ANGLE (2*LOS_MAX_RANGE-2)
#define LOS_INTERCEPT_MULT (2)
// These store all unique (in terms of footprint) full rays.
// The footprint of ray=fullray[i] consists of ray.length cells,
// stored in ray_coords[ray.start..ray.length-1].
// These are filled during precomputation (_register_ray).
// XXX: fullrays is not needed anymore after precomputation.
struct los_ray;
static vector<los_ray> fullrays;
static vector<coord_def> ray_coords;
// These store all unique minimal cellrays. For each i,
// cellray i ends in cellray_ends[i] and passes through
// thoses cells p that have blockrays(p)[i] set. In other
// words, blockrays(p)[i] is set iff an opaque cell p blocks
// the cellray with index i.
static vector<coord_def> cellray_ends;
typedef FixedArray<bit_vector*, LOS_MAX_RANGE+1, LOS_MAX_RANGE+1> blockrays_t;
static blockrays_t blockrays;
// We also store the minimal cellrays by target position
// for efficient retrieval by find_ray.
// XXX: Consider condensing this representation.
struct cellray;
static FixedArray<vector<cellray>, LOS_MAX_RANGE+1, LOS_MAX_RANGE+1> min_cellrays;
// Temporary arrays used in losight() to track which rays
// are blocked or have seen a smoke cloud.
// Allocated when doing the precomputations.
static bit_vector *dead_rays = nullptr;
static bit_vector *smoke_rays = nullptr;
class quadrant_iterator : public rectangle_iterator
{
public:
quadrant_iterator()
: rectangle_iterator(coord_def(0,0),
coord_def(LOS_MAX_RANGE, LOS_MAX_RANGE))
{
}
};
void clear_rays_on_exit()
{
delete dead_rays;
delete smoke_rays;
for (quadrant_iterator qi; qi; ++qi)
delete blockrays(*qi);
}
// LOS radius.
int los_radius = LOS_DEFAULT_RANGE;
static void _handle_los_change();
void set_los_radius(int r)
{
ASSERT(r <= LOS_RADIUS);
los_radius = r;
invalidate_los();
_handle_los_change();
}
int get_los_radius()
{
return los_radius;
}
bool double_is_zero(const double x)
{
return x > -EPSILON_VALUE && x < EPSILON_VALUE;
}
struct los_ray : public ray_def
{
// The footprint of this ray is stored in
// ray_coords[start..start+length-1].
unsigned int start;
unsigned int length;
los_ray(geom::ray _r)
: ray_def(_r), start(0), length(0)
{
}
// Shoot a ray from the given start point (accx, accy) with the given
// slope, bounded by the pre-calc bounds shape.
// Returns the cells it travels through, excluding the origin.
// Returns an empty vector if this was a bad ray.
vector<coord_def> footprint()
{
vector<coord_def> cs;
los_ray copy = *this;
coord_def c;
coord_def old;
int cellnum;
for (cellnum = 0; true; ++cellnum)
{
old = c;
if (!copy.advance())
{
// dprf("discarding corner ray (%f,%f) + t*(%f,%f)",
// r.start.x, r.start.y, r.dir.x, r.dir.y);
cs.clear();
break;
}
c = copy.pos();
if (c.rdist() > LOS_RADIUS)
break;
cs.push_back(c);
ASSERT((c - old).rdist() == 1);
}
return cs;
}
coord_def operator[](unsigned int i)
{
ASSERT(i < length);
return ray_coords[start+i];
}
};
// Check if the passed rays have identical footprint.
static bool _is_same_ray(los_ray ray, vector<coord_def> newray)
{
if (ray.length != newray.size())
return false;
for (unsigned int i = 0; i < ray.length; i++)
if (ray[i] != newray[i])
return false;
return true;
}
// Check if the passed ray has already been created.
static bool _is_duplicate_ray(vector<coord_def> newray)
{
for (los_ray lray : fullrays)
if (_is_same_ray(lray, newray))
return true;
return false;
}
// A cellray given by fullray and index of end-point.
struct cellray
{
// A cellray passes through cells ray_coords[ray.start..ray.start+end].
los_ray ray;
unsigned int end; // Relative index (inside ray) of end cell.
cellray(const los_ray& r, unsigned int e)
: ray(r), end(e), imbalance(-1), first_diag(false)
{
}
// The end-point's index inside ray_coord.
int index() const { return ray.start + end; }
// The end-point.
coord_def target() const { return ray_coords[index()]; }
// XXX: Currently ray/cellray[0] is the first point outside the origin.
coord_def operator[](unsigned int i)
{
ASSERT(i <= end);
return ray_coords[ray.start+i];
}
// Parameters used in find_ray. These need to be calculated
// only for the minimal cellrays.
int imbalance;
bool first_diag;
void calc_params();
};
// Compare two cellrays to the same target.
// This determines which ray is considered better by find_ray,
// used with list::sort.
// Returns true if a is strictly better than b, false else.
static bool _is_better(const cellray& a, const cellray& b)
{
// Only compare cellrays with equal target.
ASSERT(a.target() == b.target());
// calc_params() has been called.
ASSERT(a.imbalance >= 0);
ASSERT(b.imbalance >= 0);
if (a.imbalance < b.imbalance)
return true;
else if (a.imbalance > b.imbalance)
return false;
else
return a.first_diag && !b.first_diag;
}
enum class compare_type
{
neither,
subray,
superray,
};
// Check whether one of the passed cellrays is a subray of the
// other in terms of footprint.
static compare_type _compare_cellrays(const cellray& a, const cellray& b)
{
if (a.target() != b.target())
return compare_type::neither;
int cura = a.ray.start;
int curb = b.ray.start;
int enda = cura + a.end;
int endb = curb + b.end;
bool maybe_sub = true;
bool maybe_super = true;
while (cura < enda && curb < endb && (maybe_sub || maybe_super))
{
coord_def pa = ray_coords[cura];
coord_def pb = ray_coords[curb];
if (pa.x > pb.x || pa.y > pb.y)
{
maybe_super = false;
curb++;
}
if (pa.x < pb.x || pa.y < pb.y)
{
maybe_sub = false;
cura++;
}
if (pa == pb)
{
cura++;
curb++;
}
}
maybe_sub = maybe_sub && cura == enda;
maybe_super = maybe_super && curb == endb;
if (maybe_sub)
return compare_type::subray; // includes equality
else if (maybe_super)
return compare_type::superray;
else
return compare_type::neither;
}
// Determine all minimal cellrays.
// They're stored globally by target in min_cellrays,
// and returned as a list of indices into ray_coords.
static vector<int> _find_minimal_cellrays()
{
FixedArray<list<cellray>, LOS_MAX_RANGE+1, LOS_MAX_RANGE+1> minima;
list<cellray>::iterator min_it;
for (los_ray ray : fullrays)
{
for (unsigned int i = 0; i < ray.length; ++i)
{
// Is the cellray ray[0..i] duplicated so far?
bool dup = false;
cellray c(ray, i);
list<cellray>& min = minima(c.target());
bool erased = false;
for (min_it = min.begin();
min_it != min.end() && !dup;)
{
switch (_compare_cellrays(*min_it, c))
{
case compare_type::subray:
dup = true;
break;
case compare_type::superray:
min_it = min.erase(min_it);
erased = true;
// clear this should be added, but might have
// to erase more
break;
case compare_type::neither:
default:
break;
}
if (!erased)
++min_it;
else
erased = false;
}
if (!dup)
min.push_back(c);
}
}
vector<int> result;
for (quadrant_iterator qi; qi; ++qi)
{
list<cellray>& min = minima(*qi);
for (min_it = min.begin(); min_it != min.end(); ++min_it)
{
// Calculate imbalance and slope difference for sorting.
min_it->calc_params();
result.push_back(min_it->index());
}
min.sort(_is_better);
min_cellrays(*qi) = vector<cellray>(min.begin(), min.end());
}
return result;
}
// Create and register the ray defined by the arguments.
static void _register_ray(geom::ray r)
{
los_ray ray = los_ray(r);
vector<coord_def> coords = ray.footprint();
if (coords.empty() || _is_duplicate_ray(coords))
return;
ray.start = ray_coords.size();
ray.length = coords.size();
for (coord_def c : coords)
ray_coords.push_back(c);
fullrays.push_back(ray);
}
static void _create_blockrays()
{
// First, we calculate blocking information for all cell rays.
// Cellrays are numbered according to the index of their end
// cell in ray_coords.
const int n_cellrays = ray_coords.size();
blockrays_t all_blockrays;
for (quadrant_iterator qi; qi; ++qi)
all_blockrays(*qi) = new bit_vector(n_cellrays);
for (los_ray ray : fullrays)
{
for (unsigned int i = 0; i < ray.length; ++i)
{
// Every cell is contained in (thus blocks)
// all following cellrays.
for (unsigned int j = i + 1; j < ray.length; ++j)
all_blockrays(ray[i])->set(ray.start + j);
}
}
// We've built the basic blockray array; now compress it, keeping
// only the nonduplicated cellrays.
// Determine minimal cellrays and store their indices in ray_coords.
vector<int> min_indices = _find_minimal_cellrays();
const int n_min_rays = min_indices.size();
cellray_ends.resize(n_min_rays);
for (int i = 0; i < n_min_rays; ++i)
cellray_ends[i] = ray_coords[min_indices[i]];
// Compress blockrays accordingly.
for (quadrant_iterator qi; qi; ++qi)
{
blockrays(*qi) = new bit_vector(n_min_rays);
for (int i = 0; i < n_min_rays; ++i)
{
blockrays(*qi)->set(i, all_blockrays(*qi)
->get(min_indices[i]));
}
}
// We can throw away all_blockrays now.
for (quadrant_iterator qi; qi; ++qi)
delete all_blockrays(*qi);
dead_rays = new bit_vector(n_min_rays);
smoke_rays = new bit_vector(n_min_rays);
dprf("Cellrays: %d Fullrays: %u Minimal cellrays: %u",
n_cellrays, (unsigned int)fullrays.size(), n_min_rays);
}
static int _gcd(int x, int y)
{
int tmp;
while (y != 0)
{
x %= y;
tmp = x;
x = y;
y = tmp;
}
return x;
}
static bool _complexity_lt(const pair<int,int>& lhs, const pair<int,int>& rhs)
{
return lhs.first * lhs.second < rhs.first * rhs.second;
}
// Cast all rays
static void raycast()
{
static bool done_raycast = false;
if (done_raycast)
return;
// Creating all rays for first quadrant
// We have a considerable amount of overkill.
done_raycast = true;
// register perpendiculars FIRST, to make them top choice
// when selecting beams
_register_ray(geom::ray(0.5, 0.5, 0.0, 1.0));
_register_ray(geom::ray(0.5, 0.5, 1.0, 0.0));
// For a slope of M = y/x, every x we move on the X axis means
// that we move y on the y axis. We want to look at the resolution
// of x/y: in that case, every step on the X axis means an increase
// of 1 in the Y axis at the intercept point. We can assume gcd(x,y)=1,
// so we look at steps of 1/y.
// Changing the order a bit. We want to order by the complexity
// of the beam, which is log(x) + log(y) ~ xy.
vector<pair<int,int> > xyangles;
for (int xangle = 1; xangle <= LOS_MAX_ANGLE; ++xangle)
for (int yangle = 1; yangle <= LOS_MAX_ANGLE; ++yangle)
{
if (_gcd(xangle, yangle) == 1)
xyangles.emplace_back(xangle, yangle);
}
sort(xyangles.begin(), xyangles.end(), _complexity_lt);
for (auto xyangle : xyangles)
{
const int xangle = xyangle.first;
const int yangle = xyangle.second;
for (int intercept = 1; intercept < LOS_INTERCEPT_MULT*yangle; ++intercept)
{
double xstart = ((double)intercept) / (LOS_INTERCEPT_MULT*yangle);
double ystart = 0.5;
_register_ray(geom::ray(xstart, ystart, xangle, yangle));
// also draw the identical ray in octant 2
_register_ray(geom::ray(ystart, xstart, yangle, xangle));
}
}
// Now create the appropriate blockrays array
_create_blockrays();
}
static int _imbalance(ray_def ray, const coord_def& target)
{
int imb = 0;
int diags = 0, straights = 0;
while (ray.pos() != target)
{
coord_def old = ray.pos();
if (!ray.advance())
die("can't advance ray");
switch ((ray.pos() - old).abs())
{
case 1:
diags = 0;
if (++straights > imb)
imb = straights;
break;
case 2:
straights = 0;
if (++diags > imb)
imb = diags;
break;
default:
die("ray imbalance out of range");
}
}
return imb;
}
void cellray::calc_params()
{
coord_def trg = target();
imbalance = _imbalance(ray, trg);
first_diag = ((*this)[0].abs() == 2);
}
// Find ray in positive quadrant.
// opc has been translated for this quadrant.
// XXX: Allow finding ray of minimum opacity.
static bool _find_ray_se(const coord_def& target, ray_def& ray,
const opacity_func& opc, int range, bool cycle)
{
ASSERT(target.x >= 0);
ASSERT(target.y >= 0);
ASSERT(!target.origin());
if (target.rdist() > range)
return false;
ASSERT(target.rdist() <= LOS_RADIUS);
// Ensure the precalculations have been done.
raycast();
const vector<cellray> &min = min_cellrays(target);
ASSERT(!min.empty());
cellray c = min[0]; // XXX: const cellray &c ?
unsigned int index = 0;
if (cycle)
dprf("cycling from %d (total %u)", ray.cycle_idx, (unsigned int)min.size());
unsigned int start = cycle ? ray.cycle_idx + 1 : 0;
ASSERT(start <= min.size());
int blocked = OPC_OPAQUE;
for (unsigned int i = start;
(blocked >= OPC_OPAQUE) && (i < start + min.size()); i++)
{
index = i % min.size();
c = min[index];
blocked = OPC_CLEAR;
// Check all inner points.
for (unsigned int j = 0; j < c.end && blocked < OPC_OPAQUE; j++)
blocked += opc(c[j]);
}
if (blocked >= OPC_OPAQUE)
return false;
ray = c.ray;
ray.cycle_idx = index;
return true;
}
// Coordinate transformation so we can find_ray quadrant-by-quadrant.
struct opacity_trans : public opacity_func
{
const coord_def& source;
int signx, signy;
const opacity_func& orig;
opacity_trans(const opacity_func& opc, const coord_def& s, int sx, int sy)
: source(s), signx(sx), signy(sy), orig(opc)
{
}
CLONE(opacity_trans)
opacity_type operator()(const coord_def &l) const override
{
return orig(transform(l));
}
coord_def transform(const coord_def &l) const
{
return coord_def(source.x + signx*l.x, source.y + signy*l.y);
}
};
// Find a nonblocked ray from source to target. Return false if no
// such ray could be found, otherwise return true and fill ray
// appropriately.
// if range is too great or all rays are blocked.
// If cycle is false, find the first fitting ray. If it is true,
// assume that ray is appropriately filled in, and look for the next
// ray. We only ever use ray.cycle_idx.
bool find_ray(const coord_def& source, const coord_def& target,
ray_def& ray, const opacity_func& opc, int range,
bool cycle)
{
if (target == source || !map_bounds(source) || !map_bounds(target))
return false;
const int signx = ((target.x - source.x >= 0) ? 1 : -1);
const int signy = ((target.y - source.y >= 0) ? 1 : -1);
const int absx = signx * (target.x - source.x);
const int absy = signy * (target.y - source.y);
const coord_def abs = coord_def(absx, absy);
opacity_trans opc_trans = opacity_trans(opc, source, signx, signy);
if (!_find_ray_se(abs, ray, opc_trans, range, cycle))
return false;
if (signx < 0)
ray.r.start.x = 1.0 - ray.r.start.x;
if (signy < 0)
ray.r.start.y = 1.0 - ray.r.start.y;
ray.r.dir.x *= signx;
ray.r.dir.y *= signy;
ray.r.start.x += source.x;
ray.r.start.y += source.y;
return true;
}
bool exists_ray(const coord_def& source, const coord_def& target,
const opacity_func& opc, int range)
{
ray_def ray;
return find_ray(source, target, ray, opc, range);
}
// Assuming that target is in view of source, but line of
// fire is blocked, what is it blocked by?
dungeon_feature_type ray_blocker(const coord_def& source,
const coord_def& target)
{
ray_def ray;
if (!find_ray(source, target, ray, opc_default))
{
ASSERT(you.xray_vision);
return NUM_FEATURES;
}
ray.advance();
int blocked = 0;
while (ray.pos() != target)
{
blocked += opc_solid_see(ray.pos());
if (blocked >= OPC_OPAQUE)
return env.grid(ray.pos());
ray.advance();
}
ASSERT(false);
return NUM_FEATURES;
}
// Returns a straight ray from source to target.
void fallback_ray(const coord_def& source, const coord_def& target,
ray_def& ray)
{
ray.r.start.x = source.x + 0.5;
ray.r.start.y = source.y + 0.5;
coord_def diff = target - source;
ray.r.dir.x = diff.x;
ray.r.dir.y = diff.y;
ray.on_corner = false;
}
// Count the number of matching features between two points along
// a beam-like path; the path will pass through solid features.
// By default, it excludes end points from the count.
// If just_check is true, the function will return early once one
// such feature is encountered.
int num_feats_between(const coord_def& source, const coord_def& target,
dungeon_feature_type min_feat,
dungeon_feature_type max_feat,
bool exclude_endpoints, bool just_check)
{
ray_def ray;
int count = 0;
int max_dist = grid_distance(source, target);
ASSERT(map_bounds(source));
ASSERT(map_bounds(target));
if (source == target)
return 0; // XXX: might want to count the cell.
// We don't need to find the shortest beam, any beam will suffice.
fallback_ray(source, target, ray);
if (exclude_endpoints && ray.pos() == source)
{
ray.advance();
max_dist--;
}
int dist = 0;
bool reached_target = false;
while (dist++ <= max_dist)
{
const dungeon_feature_type feat = grd(ray.pos());
if (ray.pos() == target)
reached_target = true;
if (feat >= min_feat && feat <= max_feat
&& (!exclude_endpoints || !reached_target))
{
count++;
if (just_check) // Only needs to be > 0.
return count;
}
if (reached_target)
break;
ray.advance();
}
return count;
}
// Is p2 visible from p1, disregarding half-opaque objects?
bool cell_see_cell_nocache(const coord_def& p1, const coord_def& p2)
{
return exists_ray(p1, p2, opc_fullyopaque);
}
// We use raycasting. The algorithm:
// PRECOMPUTATION:
// Create a large bundle of rays and cast them.
// Mark, for each one, which cells kill it (and where.)
// Also, for each one, note which cells it passes.
// ACTUAL LOS:
// Unite the ray-killers for the given map; this tells you which rays
// are dead.
// Look up which cells the surviving rays have, and that's your LOS!
// OPTIMIZATIONS:
// WLOG, we can assume that we're in a specific quadrant - say the
// first quadrant - and just mirror everything after that. We can
// likely get away with a single octant, but we don't do that. (To
// do...)
// Rays are actually split by each cell they pass. So each "ray" only
// identifies a single cell, and we can do logical ORs.
// Also, rays are checked to see if they are duplicates of each
// other. If they are, they're eliminated.
// Some cellrays can also be eliminated. In general, a cellray is
// unnecessary if there is another cellray with the same coordinates,
// and whose path (up to those coordinates) is a subset, not necessarily
// proper, of the original path. We still store the original cellrays
// fully for beam detection and such.
// PERFORMANCE:
// With reasonable values we have around 6000 cellrays, meaning
// around 600Kb (75 KB) of data. This gets cut down to 700 cellrays
// after removing duplicates. That means that we need to do
// around 22*100*4 ~ 9,000 memory reads + writes per LOS call on a
// 32-bit system. Not too bad.
// IMPROVEMENTS:
// Smoke will now only block LOS after two cells of smoke. This is
// done by updating with a second array.
static void _losight_quadrant(los_grid& sh, const los_param& dat, int sx, int sy)
{
const unsigned int num_cellrays = cellray_ends.size();
dead_rays->reset();
smoke_rays->reset();
for (quadrant_iterator qi; qi; ++qi)
{
coord_def p = coord_def(sx*(qi->x), sy*(qi->y));
if (!dat.los_bounds(p))
continue;
switch (dat.opacity(p))
{
case OPC_OPAQUE:
// Block the appropriate rays.
*dead_rays |= *blockrays(*qi);
break;
case OPC_HALF:
// Block rays which have already seen a cloud.
*dead_rays |= (*smoke_rays & *blockrays(*qi));
*smoke_rays |= *blockrays(*qi);
break;
default:
break;
}
}
// Ray calculation done. Now work out which cells in this
// quadrant are visible.
for (unsigned int rayidx = 0; rayidx < num_cellrays; ++rayidx)
{
// make the cells seen by this ray at this point visible
if (!dead_rays->get(rayidx))
{
// This ray is alive, thus the end cell is visible.
const coord_def p = coord_def(sx * cellray_ends[rayidx].x,
sy * cellray_ends[rayidx].y);
if (dat.los_bounds(p))
sh(p) = true;
}
}
}
struct los_param_funcs : public los_param
{
coord_def center;
const opacity_func& opc;
const circle_def& bounds;
los_param_funcs(const coord_def& c,
const opacity_func& o, const circle_def& b)
: center(c), opc(o), bounds(b)
{
}
bool los_bounds(const coord_def& p) const override
{
return map_bounds(p + center) && bounds.contains(p);
}
opacity_type opacity(const coord_def& p) const override
{
return opc(p + center);
}
};
void losight(los_grid& sh, const coord_def& center,
const opacity_func& opc, const circle_def& bounds)
{
const los_param& dat = los_param_funcs(center, opc, bounds);
sh.init(false);
// Do precomputations if necessary.
raycast();
const int quadrant_x[4] = { 1, -1, -1, 1 };
const int quadrant_y[4] = { 1, 1, -1, -1 };
for (int q = 0; q < 4; ++q)
_losight_quadrant(sh, dat, quadrant_x[q], quadrant_y[q]);
// Center is always visible.
const coord_def o = coord_def(0,0);
sh(o) = true;
}
opacity_type mons_opacity(const monster* mon, los_type how)
{
// no regard for LOS_ARENA
if (mons_species(mon->type) == MONS_BUSH
&& how != LOS_SOLID)
{
return OPC_HALF;
}
return OPC_CLEAR;
}
/////////////////////////////////////
// A start at tracking LOS changes.
// Something that affects LOS (with default parameters)
// has changed somewhere.
static void _handle_los_change()
{
invalidate_agrid();
}
static bool _mons_block_sight(const monster* mons)
{
// must be the least permissive one
return mons_opacity(mons, LOS_SOLID_SEE) != OPC_CLEAR;
}
void los_actor_moved(const actor* act, const coord_def& oldpos)
{
if (act->is_monster() && _mons_block_sight(act->as_monster()))
{
invalidate_los_around(oldpos);
invalidate_los_around(act->pos());
_handle_los_change();
}
}
void los_monster_died(const monster* mon)
{
if (_mons_block_sight(mon))
{
invalidate_los_around(mon->pos());
_handle_los_change();
}
}
// Might want to pass new/old terrain.
void los_terrain_changed(const coord_def& p)
{
invalidate_los_around(p);
_handle_los_change();
}
void los_changed()
{
mons_reset_just_seen();
invalidate_los();
_handle_los_change();
}
↑ V799 The 'qi' variable is not used after memory has been allocated for it. Consider checking the use of this variable.


compTable using Bootstrap
This is a lousy description of what happens here.
Below are the generated comparison tables
×
Select language to compare
Please select/Empty
P-RBAC
GEO-RBAC
PERMIS


--- layout: post title: Double projection date: '2014-02-14T07:31:09+01:00' categories: - Aljubarrota - Storyboards picture_url: https://film-Storyboards.tumblr.com/post/76627415004 ---


SA Post Office backtracks on parcel delivery claim
by Staff WriterThe South African Post Office (SAPO) has backtracked on its claim that it delivers parcels without delays or problems.
The organisation said in a social media marketing campaign in October that it “delivers parcels efficiently and without delays with the margins of error reduced to zero percent”.
This claim did not go down well with some consumers, and one of them lodged a complaint with the Advertising Regulatory Board (ARB).
The complainant argued that it is impossible that the Post Office is delivering parcels with a 0% margin of error.
The Post Office responded, saying a communication error occurred in the preparation of this social media post, resulting in the disputed claim.
It added that the claim of delivering parcels without delays or problems has been removed from all social media feeds.
The ARB was satisfied the Post Office’s response to remove all the social media posts addressed the complaint.
No Comment from Post Office
MyBroadband previously asked the SA Post Office for comment regarding this marketing campaign, but the company did not reply.
SAPO Parcel Delivery Post
Below is the original social media post which claimed that the Post Office delivered parcels without delays or problems.


| 1 | /* | |
| 2 | * Copyright 2009 The Closure Compiler Authors. | |
| 3 | * | |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| 5 | * you may not use this file except in compliance with the License. | |
| 6 | * You may obtain a copy of the License at | |
| 7 | * | |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 9 | * | |
| 10 | * Unless required by applicable law or agreed to in writing, software | |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 13 | * See the License for the specific language governing permissions and | |
| 14 | * limitations under the License. | |
| 15 | */ | |
| 16 | ||
| 17 | package com.google.javascript.jscomp; | |
| 18 | ||
| 19 | import com.google.common.base.Predicate; | |
| 20 | import com.google.common.base.Supplier; | |
| 21 | import com.google.common.collect.Lists; | |
| 22 | import com.google.javascript.rhino.IR; | |
| 23 | import com.google.javascript.rhino.Node; | |
| 24 | import java.util.List; | |
| 25 | ||
| 26 | /** | |
| 27 | * Breaks up the AST at different levels for parallel analysis and | |
| 28 | * optimizations. In all cases, the subtrees are detached from the original | |
| 29 | * source tree and are replaced by place-holders for the reverse process. | |
| 30 | * Although this class breaks the AST into independent subtrees and make tree | |
| 31 | * transformation safe, it is still up to individual passes to preserve proper | |
| 32 | * semantics when analyzing the subtrees. | |
| 33 | * | |
| 34 | */ | |
| 35 | class AstParallelizer { | |
| 36 | ||
| 37 | public static final String TEMP_NAME = "JSC_TMP_PLACE_HOLDER"; | |
| 38 | ||
| 39 | private final Predicate<Node> shouldSplit; | |
| 40 | ||
| 41 | private final Supplier<Node> placeHolderProvider; | |
| 42 | ||
| 43 | private final List<Node> forest; | |
| 44 | ||
| 45 | private final Node root; | |
| 46 | ||
| 47 | private final boolean includeRoot; | |
| 48 | ||
| 49 | // Maps to place holder to the original function. | |
| 50 | private final List<DetachPoint> detachPointList; | |
| 51 | ||
| 52 | /** | |
| 53 | * Constructor. | |
| 54 | * | |
| 55 | * @param shouldSplit Specify at which node it should split the subtree. | |
| 56 | * @param shouldTraverse Specify when to stop looking for subtree to split. | |
| 57 | * This is <b>very</b> important for performance as we do not want to | |
| 58 | * traverse too much just looking for subtree. | |
| 59 | * @param placeHolderProvider Specify what type of node should be place as | |
| 60 | * a temporary place holder for where the subtree is detached. | |
| 61 | * @param root The AST itself. | |
| 62 | * @param includeRoot Should we include the root inside the forest returned | |
| 63 | * by {{@link #split()}. | |
| 64 | */ | |
| 65 | public AstParallelizer( | |
| 66 | Predicate<Node> shouldSplit, | |
| 67 | Predicate<Node> shouldTraverse, | |
| 68 | Supplier<Node> placeHolderProvider, | |
| 69 | Node root, | |
| 70 | boolean includeRoot) { | |
| 71 | this.shouldSplit = shouldSplit; | |
| 72 | this.placeHolderProvider = placeHolderProvider; | |
| 73 | this.root = root; | |
| 74 | this.includeRoot = includeRoot; | |
| 75 | this.forest = Lists.newLinkedList(); | |
| 76 | this.detachPointList = Lists.newLinkedList(); | |
| 77 | } | |
| 78 | ||
| 79 | public static AstParallelizer createNewFunctionLevelAstParallelizer( | |
| 80 | Node root, boolean globalPass) { | |
| 81 | ||
| 82 | // Split at function level. | |
| 83 | Predicate<Node> shouldSplit = new Predicate<Node>() { | |
| 84 | @Override | |
| 85 | public boolean apply(Node input) { | |
| 86 |
1
1. apply : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return input.isFunction(); |
| 87 | } | |
| 88 | }; | |
| 89 | ||
| 90 | // Always traverse until it finds a split point. | |
| 91 | Predicate<Node> shouldTraverse = new Predicate<Node>() { | |
| 92 | @Override | |
| 93 | public boolean apply(Node ignored) { | |
| 94 |
1
1. apply : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return true; |
| 95 | } | |
| 96 | }; | |
| 97 | ||
| 98 | // Use a function declaration of the same name. | |
| 99 | Supplier<Node> placeHolders = new Supplier<Node>() { | |
| 100 | @Override | |
| 101 | public Node get() { | |
| 102 |
1
1. get : mutated return of Object value for com/google/javascript/jscomp/AstParallelizer$3::get to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return IR.function(IR.name(TEMP_NAME), IR.paramList(), IR.block()); |
| 103 | } | |
| 104 | }; | |
| 105 |
1
1. createNewFunctionLevelAstParallelizer : mutated return of Object value for com/google/javascript/jscomp/AstParallelizer::createNewFunctionLevelAstParallelizer to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new AstParallelizer( |
| 106 | shouldSplit, shouldTraverse, placeHolders, root, globalPass); | |
| 107 | } | |
| 108 | ||
| 109 | public static AstParallelizer createNewFileLevelAstParallelizer(Node root) { | |
| 110 | ||
| 111 | // Split at every node that has a file name prop. | |
| 112 | Predicate<Node> shouldSplit = new Predicate<Node>() { | |
| 113 | @Override | |
| 114 | public boolean apply(Node input) { | |
| 115 |
2
1. apply : negated conditional → KILLED 2. apply : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return input.getSourceFileName() != null; |
| 116 | } | |
| 117 | }; | |
| 118 | ||
| 119 | // Use a string as place holder. | |
| 120 | Supplier<Node> placeHolders = new Supplier<Node>() { | |
| 121 | @Override | |
| 122 | public Node get() { | |
| 123 |
1
1. get : mutated return of Object value for com/google/javascript/jscomp/AstParallelizer$5::get to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return NodeUtil.newExpr(IR.string(TEMP_NAME)); |
| 124 | } | |
| 125 | }; | |
| 126 | ||
| 127 | // Only traverse blocks. | |
| 128 | Predicate<Node> shouldTraverse = new Predicate<Node>() { | |
| 129 | @Override | |
| 130 | public boolean apply(Node n) { | |
| 131 |
1
1. apply : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return n.isBlock(); |
| 132 | } | |
| 133 | }; | |
| 134 |
1
1. createNewFileLevelAstParallelizer : mutated return of Object value for com/google/javascript/jscomp/AstParallelizer::createNewFileLevelAstParallelizer to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new AstParallelizer( |
| 135 | shouldSplit, shouldTraverse, placeHolders, root, false); | |
| 136 | } | |
| 137 | ||
| 138 | /** | |
| 139 | * Remembers the split point for use in {@link #join()}. | |
| 140 | */ | |
| 141 | private void recordSplitPoint(Node placeHolder, Node before, Node original) { | |
| 142 | detachPointList.add(new DetachPoint(placeHolder, before, original)); | |
| 143 | } | |
| 144 | ||
| 145 | /** | |
| 146 | * Splits the AST into subtree at different levels. The subtrees itself are | |
| 147 | * usually not valid JavaScript but they are all subtrees of some valid | |
| 148 | * JavaScript. | |
| 149 | */ | |
| 150 | public List<Node> split() { | |
| 151 |
1
1. split : negated conditional → KILLED |
if (includeRoot) { |
| 152 | forest.add(root); | |
| 153 | } | |
| 154 |
1
1. split : removed call to com/google/javascript/jscomp/AstParallelizer::split → KILLED |
split(root); |
| 155 |
1
1. split : mutated return of Object value for com/google/javascript/jscomp/AstParallelizer::split to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return forest; |
| 156 | } | |
| 157 | ||
| 158 | private void split(Node n) { | |
| 159 | Node c = n.getFirstChild(); | |
| 160 | Node before = null; | |
| 161 |
1
1. split : negated conditional → KILLED |
while (c != null) { |
| 162 | Node next = c.getNext(); | |
| 163 |
1
1. split : negated conditional → KILLED |
if (shouldSplit.apply(c)) { |
| 164 | Node placeHolder = placeHolderProvider.get(); | |
| 165 |
1
1. split : negated conditional → KILLED |
if (before == null) { |
| 166 | forest.add(n.removeFirstChild()); | |
| 167 |
1
1. split : removed call to com/google/javascript/rhino/Node::addChildToFront → KILLED |
n.addChildToFront(placeHolder); |
| 168 | } else { | |
| 169 |
1
1. split : removed call to com/google/javascript/rhino/Node::addChildAfter → KILLED |
n.addChildAfter(placeHolder, c); |
| 170 | n.removeChildAfter(before); | |
| 171 | forest.add(c); | |
| 172 | } | |
| 173 |
1
1. split : removed call to com/google/javascript/jscomp/AstParallelizer::recordSplitPoint → KILLED |
recordSplitPoint(placeHolder, before, c); |
| 174 | before = placeHolder; | |
| 175 | } else { | |
| 176 |
1
1. split : removed call to com/google/javascript/jscomp/AstParallelizer::split → KILLED |
split(c); |
| 177 | before = c; | |
| 178 | } | |
| 179 | c = next; | |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | /** | |
| 184 | * Reverse the splitting done by {@link #split()}. | |
| 185 | */ | |
| 186 | public void join() { | |
| 187 | // Revert in a reverse order to undo the detachment. | |
| 188 |
1
1. join : negated conditional → KILLED |
while (!detachPointList.isEmpty()) { |
| 189 |
1
1. join : Replaced integer subtraction with addition → KILLED |
DetachPoint entry = detachPointList.remove(detachPointList.size() - 1); |
| 190 |
1
1. join : removed call to com/google/javascript/jscomp/AstParallelizer$DetachPoint::reattach → KILLED |
entry.reattach(); |
| 191 | } | |
| 192 | } | |
| 193 | ||
| 194 | /** | |
| 195 | * A class to map the place holder to the original subtree for re-attachment. | |
| 196 | * Normally a Map from Node -> Node is sufficient, however, if we also | |
| 197 | * remember the node before the place holder, we can avoid using | |
| 198 | * {@link Node#replaceChild(Node, Node)} which requires a linear search of | |
| 199 | * the before node. Maybe someday we should get a prev pointer for this | |
| 200 | * purpose. | |
| 201 | */ | |
| 202 | private static class DetachPoint { | |
| 203 | ||
| 204 | // The place holder to remember where the original node was. | |
| 205 | private Node placeHolder; | |
| 206 | ||
| 207 | // The node before the place holder and the original, null if | |
| 208 | private Node before; | |
| 209 | ||
| 210 | // The root of the subtree to be temporary detached. | |
| 211 | private Node original; | |
| 212 | ||
| 213 | private DetachPoint(Node placeHolder, Node before, Node original) { | |
| 214 | this.placeHolder = placeHolder; | |
| 215 | this.before = before; | |
| 216 | this.original = original; | |
| 217 | } | |
| 218 | ||
| 219 | public void reattach() { | |
| 220 | // If the place-holder no longer has a parent, this implies the function | |
| 221 | // has been removed from the AST. | |
| 222 |
1
1. reattach : negated conditional → KILLED |
if (placeHolder.getParent() != null) { |
| 223 |
1
1. reattach : negated conditional → KILLED |
if (before == null) { |
| 224 |
1
1. reattach : removed call to com/google/javascript/rhino/Node::addChildrenToFront → KILLED |
placeHolder.getParent().addChildrenToFront(original); |
| 225 | placeHolder.getParent().removeChildAfter(original); | |
| 226 | } else { | |
| 227 |
1
1. reattach : removed call to com/google/javascript/rhino/Node::addChildAfter → KILLED |
placeHolder.getParent().addChildAfter(original, before); |
| 228 | placeHolder.getParent().removeChildAfter(original); | |
| 229 | } | |
| 230 | } | |
| 231 | } | |
| 232 | } | |
| 233 | } | |
Mutations | ||
| 86 |
1.1 |
|
| 94 |
1.1 |
|
| 102 |
1.1 |
|
| 105 |
1.1 |
|
| 115 |
1.1 2.2 |
|
| 123 |
1.1 |
|
| 131 |
1.1 |
|
| 134 |
1.1 |
|
| 151 |
1.1 |
|
| 154 |
1.1 |
|
| 155 |
1.1 |
|
| 161 |
1.1 |
|
| 163 |
1.1 |
|
| 165 |
1.1 |
|
| 167 |
1.1 |
|
| 169 |
1.1 |
|
| 173 |
1.1 |
|
| 176 |
1.1 |
|
| 188 |
1.1 |
|
| 189 |
1.1 |
|
| 190 |
1.1 |
|
| 222 |
1.1 |
|
| 223 |
1.1 |
|
| 224 |
1.1 |
|
| 227 |
1.1 |


For changes in version v7.0.0 and up please go to release
- Fixed reset of BABEL_ENV when options.forceEnv is used (#420) @nikopavlica
- added metadata passing from babel to webpack, which is currently used by react-intl (#398) @Ognian
forceEnv
was interfering with regular environment handling
- The new
forceEnv
options wasn't working as expected (#379) @chrisvasz
- Add new config option
forceEnv
(#368) @moimael
Allow to override BABEL_ENV/NODE_ENV at loader-level. Useful for isomorphic applications which have separate babel config for client and server.
- Update loader-utils dependency to ^0.2.16 to fix compatibility with webpack 2 (#371) @leonaves
- Improve FS caching to do less sync calls which improves performance slightly (#375) @akx
Support for webpack 2.2-rc has been added in this release
- If cache directory not writable, try to fallback to tmpdir before failing
Source maps on windows did not work correctly with v6.2.8.
Thanks @josephst
- Add AppVeyor to run tests on windows @danez
- Fix tests on windows (#343) @danez
- gzipped files should have
.gz
as the extension, not .gzip
(#326) @bjornstar
- fix options.sourceFileName gennerate bug (#260) @creeperyang
- Update README docs for cacheDirectory's actual behaviour (#245) @sohkai
- updates docs re: transform-runtime (#197) @gbrassey
- Use eslint and nyc (#321) @danez
- Adjust travis config (#320) @danez
- Use babel to compile babel-loader (#319) @danez
Fallback to os.tmpdir()
if no cachedir found (#318) (fixes #317) @danez
Fixes an issue with v6.2.6 when using babel-loader
as a global package.
- Use standard cache dir as default
cacheDirectory
(#301) @fson
Use the common cache directory, ./node_modules/.cache/babel-loader
, as the default cache directory (when the cacheDirectory setting is enabled).
query: {
cacheDirectory: true
}
- Don't show the call stack for a Babel error (such as when you have a syntax error)
- resolve the .babelrc relative to the file path rather than the cwd (current working directory).
- fix: more concise formatting for Babel errors (#287) (Andrey Popp)
- fix(resolve-rc): resolve-rc relative file path (#253) (Luke Page)
- add babel-core and preset-2015 to dev dependencies (#273) (timse)
- chore(docs): add issue and pr templates (#280) (Joshua Wiens)
- chore(docs): fix badge formatting (Joshua Wiens)
- chore(ci): expand travis testing (#278) (Joshua Wiens)
- Update README: add env vars to cacheIdentifier (#267) (Dominik Ferber)
- add npm badge [skip ci] (Henry Zhu)
- update [skip ci] (Henry Zhu)
- remove jsx references as well [skip ci] (Henry Zhu)
- Save the transform to devDependencies (Ray Booysen)
- Remove 'react' preset (Jake Rios)
- Removed babel-preset-react from README.md (Ben Stephenson)
- change allowed peer deps (all webpack 2 beta versions)
- change allowed peer deps (2.0.7-beta)
- Update peerDependencies to accept webpack 2 #208
- Remove duplicated dependencies
- Pass true filenames #106
- Remove babel-core from devDependencies
- Merge PR #146 Set source file name relative to options.sourceRoot
- Merge PR #136 use container-based infrastructure for faster build
- Merge PR #121 Make babelrc configurable
- Merge PR #113 Include BABEL_ENV || NODE_ENV in cacheIdentifier
- Merge PR #85 - Don't override sourcemap if sourcesContent already exists.
- Merge PR #82 - Fallback global options to empty object to avoid conflicts with object-assign polyfill.
- Include
.babelrc
file into the cacheIdentifier
if it exists


--- layout: post title: How To Install Tomcat On Mac OS X date: 2015-11-15 22:29:11.000000000 +08:00 type: post published: true status: publish categories: [] tags: [] meta: _rest_api_published: '1' _rest_api_client_id: "-1" _publicize_job_id: '16877499709' author: login: noobgrammer email<EMAIL_ADDRESS>display_name: bytehala first_name: Lemuel last_name: '' ---
I've only ever tried this on my El Capitan install, but it SHOULD work on Mavericks and you should be downloading the latest OS (as of this writing) anyway.
Step 1: Go to http://tomcat.apache.org, go to Downloads, get the zip version like so:
Step 2: Unzip the file and move it into your Library folder.
Step 3: Set the environment variables. You need to set TOMCAT_HOME and JAVA_HOME. The following assumes that you have Atom text editor installed. Open terminal, and type in these commands:
[code language="bash"]
cd ~
atom .bash_profile
[/code]
This will open the file in Atom text editor. Type the following lines on your .bash_profile:
[code language="bash"]
TOMCAT_HOME="~/Library/apache-tomcat-5.5.36"
export TOMCAT_HOME
export JAVA_HOME=$(/usr/libexec/java_home)
[/code]
The above is the new recommended way for setting JAVA_HOME. There are other methods but most of them seem ineffective. Also important, do not set CATALINA_HOME if you already have TOMCAT_HOME.
Step 4: Set the permissions for the shell executables on your Tomcat directory. You might need to sudo these. In Terminal:
[code language="bash"]
cd ~/Library/your-tomcat-ver-0.0.0/bin
chmod 755 *.sh
[/code]
Step 5: Run and test your installation. Still in the bin directory,
[code language="bash" light="true"]
./startup.sh
[/code]
In your browser, go to http://localhost:8080
You should see a Tomcat welcome page.
You can stop Tomcat by running
[code language="bash" light="true"]
./shutdown.sh
[/code]


| Name: ms.Indrani | Reg No: 5-4SMMHC18 |
|---|---|
| Age / Sex:29 | Contact No:9036758047 |
| Marital Status: ml- 9 years | Date:11/4/18 |
| Occupation: housewife. 2nd pu.ba discontd | Dr. PJFP |
Address: Native of hesarughatta. |
DIAGNOSIS- |
H/O OF RHD – 2009 HAD 3 MONTH PREGNANCY THEN GOT COUGH, WEAKNESS MUCH PHLEGM AND LOT OF JOINT PAIN IT WAS DECEMBER THEN, FREQ FEVERS (USE TO HAVE RECC FVERE WITH JOINT PAIN IN CHILDHOOD AND USE TO TAKE ALLOPATHY RX.) HER GYNAC DOC SAID THT SHE WILL TREAT WELL AND USE TO GIV MED. BUT USE TO GET ON AND OFF. SHE USE TO GET SENSITIVE SMELL PROVISION STORE,ONIONS, AGARBATTI ETC AND THE PHLEGM USE TO INC.    AYURVEDA MEDICINES WAS TAKING.
OVER DEVOTION.
IN 2007 MAY HAD A FEAR INC DUE TO SEEING MOM FOOD POISOON IN HOSPITAL.
EXCESS FEAR SUICIDAL THOTS. IF SEES KNIFE THOTS TO PIERCE HER. HEIGHTS WANT TO FALL OF.
FEAR OF DEATH WHAT WILL HAPPEN IF SHE DIES AFTER OPERATION. FEELS EVERYONE ARE BLAMING HER FR ANYTHING FEELS SAD.
DEC 2017 HAD STIFF NECK AND VERY PAIN IN NECK.
PERIODS ARE LATE BY 1 N HALF MNTH. FROM THYROID DYSFUNCTION.
CONTINUOUS TALK. DOESN’T STOP. VERY WEARY AND SCARED EXPRESSION.
RX:
IGNATIA 1 M – 3 DOSES – 5 DAYS ONCE
STAPHY 1M – 5 DOSES – 3 DAYS ONCE
Rub 30 doses 1-0-1 b/food.
CACTUS 30 – DISC – 3-0-3
ACON1M – 7 DOSES – 1 DOSE NT B/FOOD WATER
19/4/18: more cough. Throat dry burning, wheezing. Night unable to sleep. Lungs tight. More headache. Neck pain. body pain is ther. Joint pain is there. From 3 days. Heat and cold all is affecting her. Mental status slightly better. Dreams constant and disturbing. Childish behavior. If anyone contradicts her or opposes her she keeps constantly thinking about that and keeps talking about the same thing. Crowded, public places doesn’t like. Wants to be home alone. Crowd gets headache. Tonsils hypertrophied and paining. No inflammation. Pain radiate to ears when inc.
Rx:
Carc1m – 1 dose now.
Ant.tart 200 – 1 dram pills – 4 pills with water sos breathing.
Conium200+baryta carb 200 4-4-4-4 1 dram pills
Bryonia 200 – 4 pills sos. Headache.


The NoC system Generator is a design flow, which can generate highly configurable NoC-based MPSoC for FPGA instantiation. The design flow has been developed to enable rapid HW/SW co-design and design space exploration (DSE) through emulation on FPGA. The generated multiprocessor platform connects the processors using the Nostrum NoC architecture and design methodology. The platform implements the distributed memory model and processors communicate using the provided communication primitives written in the C language, which are automatically generated by the flow and customized to provide services for the particular generated system.
The flow starts from a set of C application files and an XML configuration file. Through the XML file the user selects the target technology, NoC topology, kind of router and interconnection scheme. The flow automatically creates the multi processor implementation on the selected target FPGA, generates drivers to provide the communication primitives, and places the provided C application software on the cores specified by the user.Features
- Graphic User Interfacee
- Auto Generation of NoC HDL
- Xilinx and Intel/Altera Compatible
- Nostrum NoC
- Scalablility
- Reduced Development Time
The latest NSG HDLs and directory structure can be obtained from the NSG Github repository:
{% highlight bash %} $ git clone git://github.com/Noctegra/NSG.git {% endhighlight %}The NSG toolchain binaries can be found under Releases and should be downloaded and extracted to NSG/bin/windows/
Make sure to have a European (German, Swedish, etc) date & time format set (Control Panel -> Region and Language)
Visual C++ Redistributable for Visual Studio 2015
https://www.microsoft.com/en-us/download/confirmation.aspx?id=48145
Environmental Path
| Directory Name | Description |
|---|---|
| Bin/ | NSG Binaries including GUI |
| Boards/ | Boards/Platform Description Files |
| Documentation/ | NSG User Manual |
| Papers/ | List of Related Publications |
| VHDL/ | NSG HDL repo for NoC |
The 4 processors platform is configured so in this way:
In the demo application, each processor receives one data, increase the data by 1, send the data to the following processor. One data takes 1 second to be sent to the following processor. So, for example, CPU_0_0 receives the value 0, and send the value 1 to CPU_1_0. After 1 second CPU_1_0 receives the value 1, and send the value 2 to CPU_2_0....
To test the demo application there are 2 ways:
use the Nios IDE or Nios EDS to create 4 projects, each project for each CPU. The projects should start from the "Hello World small" template, or have the exact same setting in the BSP. Copy the software files (.c, .h) for each cpu in the corresponding NIOS IDE/EDS project. Build the 4 projects. Download the .sof file on the board. "Run as hardware" the projects in the following order: CPU0, 1 , 2, 3. All projects must run at the same time, do not stop them. You should see some output on the Nios2 terminals of the Nios IDE.
Open 5 Nios2 Shells. 4 shells will be used to connect to the 4 processors, 1 shell to execute the commands. For each of the 4 shell run 1 of this commands:
{% highlight bash %} $ nios2-terminal -i 1 $ nios2-terminal -i 3 $ nios2-terminal -i 4 $ nios2-terminal -i 0 {% endhighlight %}You are connected to the 4 processors through 4 terminals. Download the .sof file on the board. With the 5th shell download the provided .elf files (the compiled code) on each core using the following commands, in sequence:
{% highlight bash %} $ nios2-download -g -i 1


GETTING STARTED
Now that we have familiarized ourselves with the interface layout and navigating the Workspace, our next step is to understand the typical workflow for developing a graph in Dynamo. Let's get started by creating a dynamically sized circle and then create an array of circles with varying radii.
Defining Objectives and Relationships
Before we add anything to the Dynamo Workspace, it is key that we have a solid understanding of what we are trying to achieve and what the significant relationships will be. Remember that anytime we are connecting two Nodes, we are creating an explicit link between them - we may change the flow of data later, but once connected we've committed to that relationship. In this exercise we want to create a circle (Objective) where the radius input is defined by a distance to a nearby point (Relationship).
A point that defines a distance-based relationship is commonly referred to as an "Attractor." Here the distance to our Attractor Point will be used to specify how big our circle should be.
Adding Nodes to the Workspace
Now that we have our Objectives and Relationships sketched we can begin creating our graph. We need the Nodes that will represent the sequence of actions Dynamo will execute. Since we know we are trying to create a circle, let's start by locating a Node that does so. Using the Search field or browsing through the Library, we will find that there is more than one way to create a circle.
- Browse to Geometry > Curves > Circle > Circle.ByPointRadius
- Search > "ByCenterPointRadius..."
Let's add the Circle.ByPointRadius Node to the Workspace by clicking on it in the Library - this should add the Node to the center of the Workspace.
- The Circle.ByPointandRadius Node in the Library
- Clicking the Node in the Library adds it to the Workspace
We also will need Point.ByCoordinates, Number Input, and Number Slider Nodes.
- Geometry > Points > Point > Point.ByCoordinates
- Geometry > Geometry > DistanceTo
- Input > Basic > Number
- Input > Basic > Number Slider
Connecting Nodes with Wires
Now that we have a few Nodes, we need to connect the Ports of the Nodes with Wires. These connections will define the flow of data.
- Number to Point.ByCoordinates
- Number Sliders to Point.ByCoordinates
- Point.ByCoordinates (2) to DistanceTo
- Point.ByCoordinates and DistanceTo to Circle.ByCenterPointRadius
Executing the Program
With our Program Flow defined, all we need to do is tell Dynamo to execute it. Once our program is executed (either Automatically or when we click Run in Manual Mode), data will pass through the Wires, and we should see the results in the 3d Preview.
- (Click Run) - If the Execution Bar is in Manual Mode, we need to Click Run to execute the graph
- Node Preview - Hovering your mouse over the box on the lower right corner of a Node will give you a pop-up of the results
- 3D Preview - If any of our Nodes create geometry, we will see it in the 3D Preview.
- The output geometry on the creation node.
Adding Detail
If our program is working, we should see a circle in the 3D Preview that is passing through our Attractor Point. This is great, but we may want to add more detail or more controls. Let's adjust the input to the circle Node so that we can calibrate the influence on the radius. Add another Number Slider to the Workspace, then double click on a blank area of the Workspace to add a Code Block Node. Edit the field in the Code Block, specifying X/Y
.
- Code Block
- DistanceTo and Number Slider to Code Block
- Code Block to Circle.ByCenterPointRadius
Adding complexity
Starting simple and building complexity is an effective way to incrementally develop our program. Once it is working for one circle, let's apply the power of the program to more than one circle. Instead of one center point, if we use a grid of points and accommodate the change in the resulting data structure, our program will now create many circles - each with a unique radius value defined by the calibrated distance to the Attractor Point.
- Add a Number Sequence Node and replace the inputs of Point.ByCoordinates - Right Click Point.ByCoordinates and select Lacing > Cross Reference
- Add a Flatten Node after Point.ByCoordinates. To flatten a list completely, leave the
amt
input at the default of-1
- The 3D Preview will update with a grid of circles
Adjusting with Direct Manipulation
Sometimes numerical manipulation isn't the right approach. Now you can manually push and pull Point geometry when navigating in the background 3D preview. We can also control other geometry that was constructed by a point. For example, Sphere.ByCenterPointRadius is capable of Direct Manipulation as well. We can control the location of a point from a series of X, Y, and Z values with Point.ByCoordinates. With the Direct Manipulation approach, however, you are able to update the values of the sliders by manually moving the point in the 3D Preview Navigation mode. This offers a more intuitive approach to controlling a set of discrete values that identify a point's location.
- To use Direct Manipulation, select the panel of the point to be moved – arrows will appear over the point selected.
- Switch to 3D Preview Navigation mode.
- Hover over the point and the X, Y, and Z axes will appear.
- Click and drag the colored arrow to move the corresponding axis, and the Number Slider values will update live with the manually moved point.
- Note that before Direct Manipulation only one slider was plugged into the Point.ByCoordinates component. When we manually move the point in the X-direction, Dynamo will automatically generate a new Number Slider for the X input.


Note: I’ve written about this before, but the writing is scattered over the web and in conference keynote presentations I’ve given. This is to bring it home to one site. This code written by All Around the World is driving the narrative sci-fi MMORPG Tau Station . And if you feel the need, feel free to email us to discuss how we can build a remote software team for you. This is the quality we have been delivering for years, both for Tau Station and for our clients and therefore the quality you can expect for your own project.
Just about anyone who’s taken a beginning database course learns about the critical importance of database transactions. For example, consider the following code:
sub transfer_money ($self, $from, $to, $amount) {
if ( $from->balance < $amount ) {
Exception::InsufficientFunds->throw(...);
}
$from->dec_balance($amount);
$to->inc_balance($amount);
}
The code is a grotesque oversimplification in several ways, but let’s just look at one little line:
$from->dec_balance($amount);
What happens if that fails and throws an exception? If it fails before the money is withdrawn, that might not be disastrous. If it happens after the money is withdrawn, we withdraw the money, but don’t deposit it to the new account. Our customers will be disappointed, to put it mildly.
So we fix that with a database transaction. It might look like this:
sub transfer_money ($self, $from, $to, $amount) {
if ( $from->balance < $amount ) {
Exception::InsufficientFunds->throw(...);
}
$self->db->do_transaction(sub {
$from->dec_balance($amount);
$to->inc_balance($amount);
});
}
Now if dec_balance
fails, we’re guaranteed that whatever money was withdrawn
will still be in the original account.
But it still has a massive bug. What if money was withdrawn after we checked the balance, but before we withdrew it? Oops. It’s called a “race condition”, because the behavior of your code depends on which code finishes first.
In this case, the behavior depends on whether the system allows negative balances, whether the account allows negative balances, and other factors. We don’t want to risk this bug, so let’s expand the transaction scope.
sub transfer_money ($self, $from, $to, $amount) {
$self->db->do_transaction(sub {
if ( $from->balance < $amount ) {
Exception::InsufficientFunds->throw(...);
}
$from->dec_balance($amount);
$to->inc_balance($amount);
});
}
So now we check the transaction before we check the balance. Good to go, right?
No. Of course not. For most OO system I’ve worked on, that code is not good
to go because objects hold their data independently from the underlying
storage mechanism. What that means is that the information was read earlier
and might be stale. Instead, you need to refresh your data. But you can’t just
do a SELECT
, you need a SELECT ... FOR UPDATE
to ensure that the row is
locked in the transaction.
sub transfer_money ($self, $from, $to, $amount) {
$self->db->do_transaction(sub {
$from->requery_for_update;
$to->requery_for_update;
if ( $from->balance < $amount ) {
Exception::InsufficientFunds->throw(...);
}
$from->dec_balance($amount);
$to->inc_balance($amount);
});
}
The above is certainly better, but my goodness, there are traps there. And it still has bugs, but I’ll stop belaboring the point now.
All you wanted to do was move a bit of money from one bank account to another. And honestly, this is a simple example. When your code gets seriously complex, it can be hard to track down bugs caused by race conditions and not having proper scope on transactions.
Which brings me to the real point of this article:
The more things you must remember, the more things you will forget.
That is something that developers often gloss over.
No. You want to write systems that take failure modes into account and make it hard to write those serious bugs.
Making This Simple
So, what would the above look like in Tau Station ? Well, currently we don’t have multiple bank accounts per player, but we do have the ability to move money from your wallet to your bank account and conceptually that’s the same thing. It uses an “Exchange” system we’ve built and it looks like this:
my $exchange = $self->new_exchange(
Preamble( 'deposit' => { amount => $amount } ),
Steps(
Wallet( $self => remove_credits => $amount ),
BankAccount( $self => add_credits => $amount ),
),
);
The “Preamble” is a second that declares that messages are going to be displayed to the player and what information, if any, to use for those messages. The “Steps”, however, are only what we’re actually trying to accomplish. In other words, with our exchanges, we mostly write code that describes the desired behavior. All of the “scaffolding” code is hidden away behind the scenes.
For example, note the code we didn’t have to write, but that our exchange system handles:
- Exception handling
- Transactions
- Success messages
- Error messages
- Logging
- Checks for whether or not we had enough money
- Taxes (we have them. Long story)
And for other exchanges, we have things such as:
- Job queues for asynchronous work
- Message popups
- ... and many other details I’m omitting from this
In fact, the declarative nature of the above code means that we can even take this “exchange” and cut-n-paste it for our non-technical narrative designers and they understand what it means!
And guess what? We can reuse this. Here’s another example, reusing the
BankAccount.add_credits
code, for a relatively complex action of buying an
item from another player (a bit simplified). But first, imagine how you would
write the code for buying a physical item from a vendor and compare that code
to the following.
Steps(
Location( $self => is_in_station => $station ),
PlayerMarketItem( $self => is_not_seller_of => $item ),
PlayerMarketItem( $self => check_item_is_not_sold => $item ),
BankAccount( $self => remove_credits => $amount ),
BankAccount( $vendor => add_credits => $amount ),
Inventory( $self => add_item_instance => $item ),
PlayerMarketItem( $vendor => delete => $item ),
)
Did you think of all those steps? How much code would you have had to write
to implement all those steps? And would you have remembered all the
possible exceptions, the transactions, the SELECT ... FOR UPDATE
, and so on?
Would you have remembered or cared about all the success or failure
messages?
By writing code in such a declarative style, we have taken incredibly complex behavior and not only made it simpler, but more correct.
Here’s another example. In Tau Station, you can “save” your progress by gestating a new clone. If you die, you respawn into your latest close. What does clone gestation look like? It used to look like this mess:
sub gestate ( $self, $character ) {
croak( … ) unless $character->area->slug eq 'clonevat';
my $price = $self->price_per_character($character);
if ( $character->wallet < $price ) {
$character->add_message( … );
return;
}
my $guard = $self->result_source->schema->txn_scope_guard;
$character->dec_wallet($price);
$character->update;
my $clone = $self->find_or_new(
character_id => $character->character_id,
station_area_id => $character->station_area->station_area_id,
);
$clone->$_( $character->$_ ) for $character->physical_stats;
my $now = DateTime->now;
$clone->clone_date($now);
$clone->gestation_date(
$now->clone->add( seconds => $self->gestation_delay($character) ) );
$clone->update_or_insert;
$character->add_message( … );
$guard->commit;
return $clone;
}
And that was a bucket of bugs. And hard to follow. Now it looks like this:
Steps(
Location( $self => is_in_area => 'clonevat' ),
Wallet( $self => pay => $price ),
Clone( $self => gestate => $area ),
),
Honestly, which of those would you rather write?
Declarative Exchanges
So how does this magic work?
The Behavior
When you create a new exchange, the first thing it does is go through your steps and figure out what objects might be updated. Then we:
- Start a transaction
- Refresh all assets via
SELECT...FOR UPDATE
- Run all the steps
- Commit on success and rollback on failure
- Notify the player(s) (if appropriate)
It sounds simple, but there’s a lot more going on under the hood. For example, if you are a member of a syndicate and you earn income, you may have to pay “tax” to that syndicate. Thus, the exchange needs to know that it must fetch the syndicate object, lock it, and send taxes to it. As a developer writing the code, you almost never have to pay attention to this. It’s all automatic.
The Structure
Each exchange step looks very similar:
Location( $self => is_in_area => 'clonevat' )
In exhange parlance, that’s:
Topic( subject => verb => object )
Everything follows a linguistic SVO (subject-verb-object) pattern. To create a
new Topic for the exchanges, you create a class called
Veure::Economy::Asset::Topic
(there are legacy reasons for the
name) and have it inherit from Veure::Economy::Asset
. We have another system
that automatically finds and loads all these classes and ensures that the
asset name is exportable on demand. You just write the code, there’s no need
to wire it together because that’s done for you.
Each of these classes takes a subject (the first argument) and implementing a
verb is merely a matter of writing a method. The object (in linguisitic terms)
becomes the argument(s) to the method. A simple is_in_area
check might look
like this:
sub is_in_area ( $self, $area_slug ) {
my $station_area_id = $self->station_area->area_id;
if ( $self->station_area->area_slug eq $area_slug ) {
return $self->new_outcome( success => 1 );
}
# give them a nice failure message
return $self->new_outcome(
success => 0,
message => ...
);
}
Simple, eh? And now we can reuse this to our heart’s content.
Failure
Aside from the fact that the exchanges allow us to write incredibly complex code very quickly, one of my favorite parts is the fact that even though it’s mostly declarative on the surface, underneath it’s objects all the way down. That means we get the full power of OO introspection where we need it. For example, what happens if I’m running the test suite and an exchange throws an exception?
Well, of course, we get a stack trace. And at the top of that trace, we get a stringified version of the exchange. In this case, it’s for refueling a spaceship:
character('ovid')->new_exchange(
slug => 'refuel-current-ship',
success_message => 'Your ship is now being refueled.',
failure_message => 'Unable to refuel ship.',
Steps(
Area( character('ovid'), is_in, docks ),
Ship( ship('ovid', 'bootlegger'), is_docked_on, tau-station ),
Ship( ship('ovid', 'bootlegger'), needs_refueling ),
Character( character('ovid'), not_onboard_ship,
ship('ovid', 'bootlegger')
),
Money( character('ovid'), pay, -15.00 ),
Character( character('ovid'), refuel_ship, ship('ovid', 'bootlegger') ),
Character( character('ovid'), set_cooldown,
{ship => ship('ovid', 'bootlegger'),
cooldown_type => 'ship_refuel',period => 1000} ),
)
);
In this case, we got an exception because there’s a serious bug: somehow the character has been asked to pay negative credits. This stringified exchange shows this very clearly here:
Money( character('ovid'), pay, -15.00 ),
So it’s dead simple to recreate conditions that cause failures in incredibly complex behavior. In this case, we knew our exchange system was fine, but something was sending it bad data.
Regrets
If there is one regret I have about the exchange system, it’s that it’s not open-source. We absolutely would release this if we could, but when we started on it, it wasn’t clear what the end result would be. Thus, it’s deeply tied to our game Tau Station . If we find ourselves with the time—or a contract—for this, we will release this for everyone.
As an aside, Ruby has something rather similar, named Trailblazer . The main difference in exchanges is that we’re not tied to MVC or the web. Trailblazer documents itself as “A New Architecture For Rails”, suggesting a tight coupling. That being said, it has fantastic testimonials which match our internal experience with exchanges. I expect we might see more of this type of code in the future.


What is the Tech Radar?
The Silicon Jungles Tech Radar is a list of technologies,
complemented by an assessment result, called
ring assignment. We use four rings with the following
semantics:
-
ADOPT — Technologies we have high
confidence in to serve our purpose, also in large scale.
Technologies with a usage culture in our production environment,
low risk and recommended to be widely used.
-
TRIAL — Technologies that we have seen work
with success in project work to solve a real problem; first
serious usage experience that confirm benefits and can uncover
limitations. TRIAL technologies are slightly more risky; some
engineers in our organization walked this path and will share
knowledge and experiences.
-
ASSESS — Technologies that are promising
and have clear potential value-add for us; technologies worth to
invest some research and prototyping efforts in to see if it has
impact. ASSESS technologies have higher risks; they are often
brand new and highly unproven in our organisation. You will find
some engineers that have knowledge in the technology and promote
it, you may even find teams that have started a prototyping
effort.
-
HOLD — Technologies not recommended to be
used for new projects. Technologies that we think are not (yet)
worth to (further) invest in. HOLD technologies should not be used
for new projects, but usually can be continued for existing
projects.
|
What is the purpose?
The Tech Radar is a tool to inspire and support engineering teams at
Silicon Jungles to pick the best technologies for new projects. It
provides a platform to share knowledge and experience in
technologies, to reflect on technology decisions and continuously
evolve our technology landscape. Based on the
pioneering work of ThoughtWorks
and Zalando, our Tech Radar sets out the changes in technologies
that are interesting in software development — changes that we
think our engineering teams should pay attention to and consider
using in their projects.
How do we maintain it?
The Tech Radar is currently an experiment. If successful, it will be
maintained by our senior developers and architects.
|


Uses of Package
org.drip.param.definition
| Package | Description |
|---|---|
| org.drip.analytics.definition |
Latent State Curves, Surfaces, Turns
|
| org.drip.analytics.support |
Assorted Support and Helper Utilities
|
| org.drip.param.creator |
Market Curves Surfaces Quotes Builder
|
| org.drip.param.definition |
Latent State Quantification Metrics Tweak
|
| org.drip.param.market |
Curves Surfaces Quotes Fixings Container
|
| org.drip.param.pricer |
Pricing Parameters Customization Settings Control
|
| org.drip.param.quote |
Multi-sided Multi-Measure Ticks Quotes
|
| org.drip.product.creator |
Streams and Products Construction Utilities
|
| org.drip.product.definition |
Fixed Income Components/Baskets Definitions
|
| org.drip.state.basis |
Basis State Curve Construction/Estimation
|
| org.drip.state.boot |
Bootable Discount, Credit, Volatility States
|
| org.drip.state.creator |
Scenario State Curve/Surface Builders
|
| org.drip.state.curve |
Basis Spline Based Latent States
|
| org.drip.state.forward |
Forward Latent State Curve Estimator
|
| org.drip.state.fx |
FX Latent State Curve Estimator
|
| org.drip.state.govvie |
Govvie Latent State Curve Estimator
|
| org.drip.state.nonlinear |
Nonlinear (i.e., Boot) Latent State Construction
|
| org.drip.state.repo |
Latent State Repo Curve Estimator
|
| org.drip.state.representation |
Latent State Merge Sub-stretch
|
-
Classes in org.drip.param.definition used by org.drip.analytics.definition Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.analytics.support Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.param.creator Class Description ProductQuote ProductQuote abstract class holds the different types of quotes for a given product.Quote Quote interface contains the stubs corresponding to a product quote.ScenarioMarketParams ScenarioMarketParams is the place holder for the comprehensive suite of the market set of curves for the given date. -
Classes in org.drip.param.definition used by org.drip.param.definition Class Description CalibrationParams CalibrationParams the calibration parameters - the measure to be calibrated, the type/nature of the calibration to be performed, and the work-out date to which the calibration is done.ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat).ProductQuote ProductQuote abstract class holds the different types of quotes for a given product.Quote Quote interface contains the stubs corresponding to a product quote. -
Classes in org.drip.param.definition used by org.drip.param.market Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat).ProductQuote ProductQuote abstract class holds the different types of quotes for a given product.ScenarioMarketParams ScenarioMarketParams is the place holder for the comprehensive suite of the market set of curves for the given date. -
Classes in org.drip.param.definition used by org.drip.param.pricer Class Description CalibrationParams CalibrationParams the calibration parameters - the measure to be calibrated, the type/nature of the calibration to be performed, and the work-out date to which the calibration is done. -
Classes in org.drip.param.definition used by org.drip.param.quote Class Description ProductQuote ProductQuote abstract class holds the different types of quotes for a given product.Quote Quote interface contains the stubs corresponding to a product quote. -
Classes in org.drip.param.definition used by org.drip.product.creator Class Description ScenarioMarketParams ScenarioMarketParams is the place holder for the comprehensive suite of the market set of curves for the given date. -
Classes in org.drip.param.definition used by org.drip.product.definition Class Description ScenarioMarketParams ScenarioMarketParams is the place holder for the comprehensive suite of the market set of curves for the given date. -
Classes in org.drip.param.definition used by org.drip.state.basis Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.boot Class Description CalibrationParams CalibrationParams the calibration parameters - the measure to be calibrated, the type/nature of the calibration to be performed, and the work-out date to which the calibration is done. -
Classes in org.drip.param.definition used by org.drip.state.creator Class Description CalibrationParams CalibrationParams the calibration parameters - the measure to be calibrated, the type/nature of the calibration to be performed, and the work-out date to which the calibration is done. -
Classes in org.drip.param.definition used by org.drip.state.curve Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.forward Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.fx Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.govvie Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.nonlinear Class Description CalibrationParams CalibrationParams the calibration parameters - the measure to be calibrated, the type/nature of the calibration to be performed, and the work-out date to which the calibration is done.ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.repo Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat). -
Classes in org.drip.param.definition used by org.drip.state.representation Class Description ManifestMeasureTweak ManifestMeasureTweak contains the place holder for the scenario tweak parameters, for either a specific curve node, or the entire curve (flat).


|
KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
|
This function provides essential capabilities for mapping between local and global ids in a distributed vector. More...
#include <distributed_numbering.h>
Public Member Functions | |
Life Cycle | |
| DistributedNumbering (const DataCommunicator &rComm, const IndexType LocalSize) | |
| DistributedNumbering (const DataCommunicator *pComm, const IndexType LocalSize) | |
| DistributedNumbering (const DataCommunicator &rComm, const IndexType TotalSize, const MpiIndexType Nranks) | |
| DistributedNumbering (const DataCommunicator *pComm, const IndexType TotalSize, const MpiIndexType Nranks) | |
| DistributedNumbering (const DataCommunicator *pComm, const std::vector< IndexType > &CpuBounds) | |
| DistributedNumbering (const DataCommunicator &rComm, const std::vector< IndexType > &CpuBounds) | |
| DistributedNumbering (const DistributedNumbering &rOther) | |
| Copy constructor. More... | |
| ~DistributedNumbering () | |
| Destructor. More... | |
Type Definitions | |
| typedef TIndexType | IndexType |
| typedef int | MpiIndexType |
| KRATOS_CLASS_POINTER_DEFINITION (DistributedNumbering) | |
| Pointer definition of DistributedNumbering. More... | |
Operators | |
| const DataCommunicator & | GetComm () const |
| const DataCommunicator * | pGetComm () const |
| IndexType | LocalSize () const |
| IndexType | Size () const |
| bool | IsLocal (const IndexType I) const |
| IndexType | LocalId (const IndexType rGlobalId) const |
| IndexType | GlobalId (const IndexType rLocalId) const |
| IndexType | RemoteLocalId (const IndexType rGlobalId, const IndexType rOwnerRank) const |
| IndexType | RemoteGlobalId (const IndexType rRemoteLocalId, const IndexType rOwnerRank) const |
| IndexType | OwnerRank (const IndexType RowIndex) const |
| const std::vector< IndexType > & | GetCpuBounds () const |
| std::string | Info () const |
| Turn back information as a string. More... | |
| void | PrintInfo (std::ostream &rOStream) const |
| Print information about this object. More... | |
| void | PrintData (std::ostream &rOStream) const |
| Print object's data. More... | |
This function provides essential capabilities for mapping between local and global ids in a distributed vector.
| typedef TIndexType Kratos::DistributedNumbering< TIndexType >::IndexType |
| typedef int Kratos::DistributedNumbering< TIndexType >::MpiIndexType |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
Copy constructor.
|
inline |
Destructor.
|
inline |
|
inline |
|
inline |
|
inline |
Turn back information as a string.
|
inline |
| Kratos::DistributedNumbering< TIndexType >::KRATOS_CLASS_POINTER_DEFINITION | ( | DistributedNumbering< TIndexType > | ) |
Pointer definition of DistributedNumbering.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
Print object's data.
|
inline |
Print information about this object.
|
inline |
|
inline |
|
inline |


This package can not be installed on your system.
This package can not be installed on your system, but can be quick played in the client.
Oh no! We couldn't download this package. Perhaps check that you're still online?
Oh no! We couldn't unpack this package after downloading it. Maybe try again?
Oh no! We couldn't remove this package. Maybe try again?
You are currently running this package. Some options have been disabled while it's open.


SPANKING THE MONKEY (1994) A Film Review by Ted Prigge Copyright 1997 Ted Prigge
Writer/Director: David O. Russel Starring: Jeremey Davies, Alberta Watson, Benjamin Hendrickson,
Now, first off, the title doesn't really do the film a lot of justice.  This film does deal with the topic of masturbation, but it also deals with such non-conformist topics like incest, rape (not the real kind, the legal kind), and insanity. It's not just one of the members in a long line of films that are in some way trying to be the 90s answer to "The Graduate" (an impossible task, in my opinion), but also an ingenius black comedy and intense character study.
Jeremey Davies is an MIT student, coming home for a week or two in the summer to take care of his bedridden mother (Alberta Watson)who has just broken her leg. His father (Benjamin Hendrickson) is a travelling salesman and can't afford to stay home for a summer and take care of his wife, especially since they both don't share any kinds of feelings other than belonging anymore. So he shocks his son, who was supposed to attend a summer program dealing with his major, by telling him he'll be spending the entire summer at home with his mother, who is totally depressed.
The film starts off funny in that kind of off-beat way. You giggle at some of the little things that happen, and laugh out loud at some of the funnier parts. But then your jaw begins to drop at some of the weirder and more outrageous plot twists, like when he has to hold his naked mother up while she takes a shower, and he begins looking at her...
He also begins a little relationship with a soon-to-be junior in high school who wants to go to MIT, and watches as they begin to have sexual feelings for eachother. But of course, he has his mother to not only take care of, but there's that bond between the two that cannot be broken, and that will gradually drive him into a bit of insanity.
What's great about this film is how well the characterization is. The bond between the mother and son is a very intense one. Through talking, we find out that she wanted to do the same thing he is studying, but she made a deal with his father to give it up and have him. So he's the price she paid for her loneliness and manic depression, and she seems hell-beant on keeping him, even if it causes him some emotional depravation.
Also great in this film is the great acting from all involved, especially the two leads. Davies shows promise as a young actor, while Watson gives an Oscar worthy performance on par with that of Anne Bancroft in "The Graduate." While this may not be as great as "The Graduate," it's at least as close as we're gonna get to recreating it, even if it's the more liberal "Graduate."
It's hard for me to reccomend this film. Afterwards, I felt horrible. Of course, that is precisely what David O. Russel had in mind, so I can say that this is a great example of fine cinematic craftsmanship. The film is utterly depressing in every way, in such a way that I would have to wait a long time to see it again. Yes, it's funny, but it's such a miserable-inducing film that I'd only reccomend it to those who are very mature. Any horny sophomoric from junior high who wants to view it as a prerequisite for entering the Beavis and Butthead club should just skip out and go for that porno with the same name.
MY RATING (out of 4): ***1/2
Homepage at: http://www.geocities.com/Hollywood/Hills/8335
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Queensland mother remanded in custody over death of two daughters found inside car
by Australian Associated PressKerri-Ann Conley, 27, is the first person to be charged under Queensland’s new definition of murder
The mother of two girls who died after exposure to extreme heat inside a car has been remanded in custody after her case went to court.
Kerri-Ann Conley, 27, has been charged with two counts of murder and two drug-related charges. She is the first person to be charged under Queensland’s new definition of murder, which includes reckless indifference to human life.
She did not appear when her matter was mentioned in Brisbane magistrates court on Monday. Conley was remanded in custody to appear in Beenleigh magistrates court on 11 December.
The one and two-year-old sisters died inside a black station wagon parked across the front yard of their family home in Logan, south of Brisbane on Saturday.
Paramedics were called but could not revive the one- and two-year-old sisters. They were declared dead at the scene.
Police say the girls showed signs of being exposed to extreme heat.
Officers remained at the home on Sunday, piecing together what happened. Neighbours and community members came and went throughout the day, leaving teddybears and flowers at the front gate, metres from where the black station wagon was parked across the yard.
Premier Annastacia Palaszczuk on Monday said the state’s child safety department had been engaged with the family and will now conduct a child death review, as is protocol.
Attorney general Yvette D’ath will ask Cheryl Vardon, the Queensland Family and Child Commission’s principal commissioner, to investigate what happened.
Palaszczuk said she would release those findings.
“The death of these two young girls is an absolute tragedy,” she said.
“I was heartbroken when I heard about it, I think everybody would be in exactly the same position.”
Child safety minister Di Farmer has said her department would offer police any assistance needed in their investigation.


I love this site because of the hilarious content first and foremost...and I also think it is pretty good looking. I like its simple fonts and the uniformity of formal elements. I also like the red, white and black color scheme. I feel like color schemes that have a lot of secondary colors look cheesy because they clash with the photos (obviously I am aware that my site is quite cheesy). Having red just makes the photos pop and everything still seems to match.
At first glance my eye is drawn to the large slideshow photo on the top left. After stepping back, I think my eye is also drawn to the "Join TRI!" announcement and the logo on top.
As for the presentation on the site, I would say the site is minimalist, a little tacky, has a hip hop vibe, is organized, and easily readable.
This site provides quick and light entertainment for those who are into rap and satirical news. It solves the problem of, "can there be a "The Onion" of hip hop?
Regarding the contect of the site, I would say it is pop-culture-oriented, subversive, sarcastic, and silly, and critical.
Browsing through ALL the content is not that easy. From how the site is laid out, its difficult to get an accurate sense of how many posts there are. Might be intentional since this is not real news so the stuff knd of expires faster and looking at old posts is not very common.
After being on the site for a while, I get the feeling that I have spent my break in a fun way, "wasting time" but in a nice and pleasant way.
The site sells t shirts, I have not purchased one but I would like to!
When I am about to get on the train and know I am going to be bored, I try to quickly load some interesting pop cultural articles from here.
First place my eye is drawn is the ad on top.
I would describe the site as cluttered, busy, classic, somewhat good-looking, hipster, nerdy, cool.
The web site solves the problem of filling the niche for high-brow type people looking to read some interesting stories on pop cultural stuff of with an upper-middle class white interest slant, more low-brow type things.
The web site solves the problem of filling the niche for high-brow type people with pper-middle class white interests who arelooking to read some interesting stories on pop cultural stuff including more low-brow type things.
I would describe the content as snarky, pretentious, silly, hip, liberal.
I think this site is very difficult to navigate, Its hard to fine everything, and there is a lot going on.
After being on the site for a while I often feel frustrated having looked for something to read for a while and getting stuck going in circles or just having diffuculty finding something that interestes me because of how disorganized it is.
The site doesn't sell anything as far as I know (other than the stuff it advertises).
I use this site often because I love knowing rap lyrics and reading people's interpretations of their meanings.
My eye is drawn to the Genius logo. Visually, this web site is dark, masculine, edgy, stylish, and a little busy.
This web site solves a few problems: where can one get reliable lyrics for every type pf music? Where can people read about the meanings of these lyrics, including the meanings according the general public as well as according to the artist? And where can people post their interpretations? And now, more recently and over time, the site answers the question of, where can people annotate/find annotations on anything and everything? If Wikipedia is where you can find out what things are, Genius is where you can find out what they mean, line by line if its a text, second by second if its a film, etc etc.
I would describe the content, focus, and purpose of the site as: ambitious, information-heavy, complex, philosophical, "meta", systematic, knowledge-spreading, important, and fascinating. I think that the site is visually somewhat incongruous with its aims, however it all started with rap and I see that in the presentation. Maybe they would benefit form making the site more bland and wikipedia-like if they want it to be considered a one stop shop for opinion collections that are aggregated, monitored and moderated by unbiased individual.
It is somewhat difficult to find things on the site. There is a bug wherein if you scroll to the bottom to read the information on the footer, contents will continue loading on the page, so the footer will move down and you'll have to scroll again, etc etc ad infinitum! So in some cases its impossible to find information if what you are looking for is on the footer.
It's also very difficult to understand what happened to your annotations taht you have made after you made them. I think that it would be a very difficult process to represent well visually, but I think their current method is pretty bad.
I love looking on the site for long periods of time, reading about the lyrics of my favorite rappers and getting to know them better as artists. I especially love reading the artist's own annotations. The site doesn't sell anything.