swarm-support
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Segmentation Fault Blues...


From: bleydorf
Subject: Segmentation Fault Blues...
Date: Thu, 21 Aug 1997 16:11:39 -0400

Hi,
(Background info: The "simple" simulation I am attempting to create is
called Problems, Problems are agents which will scury around a "world"
looking for solutions(also agents).  For now, the problems (and
solutions) are assigned a random integer, and then the problems look for
solutions which are nearest to their value.)

But, I haven't gotten that far yet, I took heatbugs, and "converted" it
to the problems simulation.  At first, I created both problem agents,
solution agents, the Neighborhood (which I realized I didnt need), and
the model and observer swarms.  After I got the "segmentation fault"
error, yesterday, in an effort to remove all "unnecessary" code, so I
took out all stuff dealing with the solution agents and the neighborhood
stuff.  
As the code exists now, all it "should" do, is create the Problem
agents, in a world much like heatbugs, and then the agents should move
randomly.  But, now when I hit, "GO" it returns a "segmentation fault
error". 

As Ted suggested yesterday, I attempted to use gdb to debug it, but
(either I didnt know how to use gdb, or it didnt like it), so that
didn't seem to work.

So, I have enclosed my "simplified code" as well as the makefile I used,
if anyone has a couple minutes could they look over it, and tell me if
it looks OK.  For the life of me, I've really hit a "WALL".  If anyone
wants to give me a quick tutorial on gdb, or how I could use gdb to
diagnose this problem I would also appreciate it.

Thanks,
Brad.

ps. Code follows:

> The following is the simplified version of the Problem simulation, at the 
> beginning of each file, there will
> be a "//" describing which file it is.
> 
> //Makefile  
> 
> SWARMHOME=/usr/src/swarm-1.0.2
> APPLICATION=problems
> OBJECTS=Problem.o  main.o ProblemModel.o ProblemObserver.o
> APPLIBS=-lspace
> OTHERCLEAN=
> 
> include $(SWARMHOME)/Makefile.appl
> 
> 
> main.o: main.m Problem.h ProblemObserver.h
> Problem.o: Problem.m Problem.h
> ProblemObserver.o: ProblemObserver.m ProblemObserver.h ProblemModel.h
> ProblemModel.o: ProblemModel.m ProblemModel.h
> 
> 
> 
> // main.m
> 
> #import <simtools.h>                // ... for initSwarm() and swarmGUIMode
> #import "ProblemObserver.h"
> 
> int
> main(int argc, char ** argv) {
>   id theTopLevelSwarm ;
> 
>   initSwarm(argc, argv);
>   theTopLevelSwarm = [ProblemObserver create: globalZone];
> 
>   [theTopLevelSwarm buildObjects];
>   [theTopLevelSwarm buildActions];
>   [theTopLevelSwarm activateIn: nil];
>   [theTopLevelSwarm go];
> 
>   // theTopLevelSwarm has finished processing, so it's time to quit.
>   return 0;
> }
> 
> 
> 
> // Problem.h (Heatbug.h)
> 
> #import <space.h>                               // we use Space features
> #import <tkobjc/Raster.h>                       // special class for graphics
> 
> // The definition of a Problem object. We inherit code from the generic
> // SwarmObject, which provides memory allocation and other niceties. It
> // does not provide any sort of agent behaviour, though, that's up to us.
> // First, heatbugs have a lot of state variables:
> 
> @interface Problem: SwarmObject {
> 
>   int idealNumber;
>   int x, y;                                     // my spatial coordinates
>   float problemRandomMoveProb;                          // chance of moving 
> randomly
>   
>   Grid2d * world;                               // the world I live in
>   int worldXSize, worldYSize;                   // how big that world is
>   Color problemColor;                           // my colour (display)
>   id problemPixmap;                             // my pixmap (display)
> }
> 
> // these methods are used to initialize the object's state. First,
> // methods that have to be sent to create an object.
> 
> -setWorld: (Grid2d *) w;                        // which world are we in?
> 
> // As a convention, we put the -createEnd here to indicate that we're done
> // defining new methods that are required before createEnd.
> 
> -createEnd;
> 
> // Other methods to set Heatbug state. These can be called after the
> // object has been fully created.
> 
> -setIdealNumber: (int) i;
> -setRandomMoveProbability: (float) p;
> -setX: (int) x Y: (int) y;              // problem's position
> -setProblemColor: (Color) c;            // problem's colour (display)
> -setPixmap: pm;                                 // problem's pixmap (display)
> 
> // The major problem behavior: do one "time step".
> 
> -step;
> 
> // extra display code (problems currently draw themselves)
> 
> -drawSelfOn: (Raster *) r;
> 
> @end
> 
> 
> // Problem.m (Heatbug.m)
> 
> #import "Problem.h"
> #import <simtools.h>
> 
> // Defining the methods for a Problem.
> 
> @implementation Problem
> 
> // Initialize crucial state for the heatbug.
> 
> -setWorld: (Grid2d *) w {
> 
>   // Strictly speaking, this check isn't necessary. But we intend these
>   // parameters to be immutable once set, so to be extrasafe we check:
>   // it could catch an error later.
> 
>   if (world != nil) {
>     [InvalidArgument raiseEvent: "You can only set the world of a problem at 
> once at creation time\n"];
>   }
>   world = w;
> 
>   return self;
> }
> 
> // createEnd. This is a good place to put code that does various sorts
> // of initialization that can only be done after some parameters of the
> // object are set. It's also a good time to check for errors in creation.
> 
> -createEnd {
> 
>   // make sure the user set up world.
> 
>   if (world == nil) {
>     [InvalidCombination raiseEvent: "Problem was created without a world.\n"];
>   }
> 
>   // Cache the worldSize for speed of later access. 
> 
>   worldXSize = [world getSizeX];
>   worldYSize = [world getSizeY];
> 
>   return self;                                          // CRUCIAL!
> }
> 
> // Simple set methods for Problem state. 
> 
> -setIdealNumber: (int) i {
>   idealNumber = i;
>   return self;
> }
> 
> -setRandomMoveProbability: (float) p {
>   randomMoveProbability = (float) p;
>   return self;
> }
> 
> // This method is a bit dangerous: we blindly put ourselves on top of
> // the grid no matter what's underneath us: because Grid2d only allows
> // one object per square, we could be destroying data.
> 
> -setX: (int) inX Y: (int) inY {
>   x = inX;
>   y = inY;
>   [world putObject: self atX: x Y: y];                  // yikes!
>   return self;
> }
> 
> // All of the previous code is basic Swarm object programming. The
> // real simulation code follows.
> 
> // Problem behaviour is actually implemented here. The notion of a "step"
> // method is a nice simplification for basic simulations.
> 
> -step {
>   int newX, newY;
>   int tries;
> 
>   // update my current unhappiness value: abs(ideal - here);
> 
>   if (((float)[uniformDblRand
>         getDoubleWithMin: 0.0 withMax: 1.0]) < randomMoveProbability) {
> 
>     newX = (x +
>             [uniformIntRand
>               getIntegerWithMin: -1L withMax: 1L]); // pick a random spot
> 
>     newY = (y + [uniformIntRand getIntegerWithMin: -1L withMax: 1L]);
> 
>     newX = (newX + worldXSize) % worldXSize;      // normalize coords
>     newY = (newY + worldYSize) % worldYSize;
>   }
> 
>   // Part of the heatbug simulation is that two bugs cannot be in the
>   // same spot. The code to enforce that is done here: ...
> 
>   tries = 0;
>   while ([world getObjectAtX: newX Y: newY] != nil && tries < 10) {
>   newX = (x + [uniformIntRand getIntegerWithMin: -1L withMax: 1L] +
>             worldXSize) % worldXSize;
>     newY = (y + [uniformIntRand getIntegerWithMin: -1L withMax: 1L] +
>             worldYSize) % worldYSize;
> 
>     tries++;                                    // don't try too hard.
>   }
>   if (tries == 10) {                            // no nearby clear spot
>     newX = x;                                   // so just don't move.
>     newY = y;
>   }
> 
>   // Ok, we've found a spot to move to...
>   // Now move ourselves in the grid and update our coordinates.
> 
>   [world putObject: nil atX: x Y: y];
>   x = newX;
>   y = newY;
>   [world putObject: self atX: newX Y: newY];
> 
>   // all done moving! Return self.
> 
>   return self;
> }
> 
> // Extra bits of display code: setting our colour, drawing on a window.
> // This code works, but it'd be better if there were a generic object
> // that knew how to draw agents on grids.
> 
> -setProblemColor: (Color) c {
>   problemColor = c;
>   return self;
> }
> 
> -setPixmap: pm {
>   problemPixmap = pm;
>   return self;
> }
> 
> -drawSelfOn: (Raster *) r {
>   [r draw: problemPixmap X: x Y: y];
>   return self;
> }
> 
> @end
> 
> 
> // ProblemModelSwarm.h
> 
> #import "Problem.h"
> #import <space.h>
> #import <activity.h>
> #import <collections.h>
> #import <swarmobject/Swarm.h>
> #import <tkobjc.h>
> #import <swarmobject.h>
> 
> @interface ProblemModel : Swarm {
> 
>   int numProblems;                       // simulation parameters
>   int worldXSize, worldYSize;
>   int minIdealNumber, maxIdealNumber;
>   double problemRandomMoveProb;
> 
>   id modelActions;                              // scheduling data structures
>   id modelSchedule;
> 
>   id problemList;                               // list of all the problems
>   Grid2d * world;                               // The neighborhood
>   XPixmap *problemPixmap;                       // problem's pixmap
>  
> }
> 
> -getProblemList;                                          // access methods 
> into the
> 
> -(Grid2d *) getWorld;                        // model swarm. These methods
>                                                         // allow the model 
> swarm to
>                                              // be observed.
> 
> +createBegin: (id) aZone;                            // extra methods you
> -createEnd;                                  // provide for Swarms
> -buildObjects;
> -buildActions;
> -activateIn: (id) swarmContext;
> 
> @end
> 
> 
> 
> //ProblemModelSwarm.m
> 
> #import "ProblemModel.h"
> #import <simtools.h>
> 
> @implementation ProblemModel
> 
> // These methods provide access to the objects inside the ModelSwarm.
> // These objects are the ones visible to other classes via message call.
> // In theory we could just let other objects use Probes to read our state,
> // but message access is frequently more problemvenient.
> 
> -getProblemList {
>   return problemList;
> }
> 
> -getWorld {
>   return world;
> }
> 
> 
> // createBegin: here we set up the default simulation parameters.
> 
> +createBegin: (id) aZone {
>   ProblemModel * obj;
>   ProbeMap * probeMap;
> 
>   // First, call our superclass createBegin - the return value is the
>   // allocated ProblemModel object.
> 
>   obj = [super createBegin: aZone];
> 
>   // Now fill in various simulation parameters with default values.
> 
>   obj->numProblems = 50;
>   obj->worldXSize = 80;
>   obj->worldYSize = 80;
>   obj->minIdealNumber = 1;
>   obj->maxIdealNumber = 50;
>   obj->problemRandomMoveProb = 0.9;
> 
>   // And build a customized probe map. Without a probe map, the default
>   // is to show all variables and messages. Here we choose to
>   // customize the appearance of the probe, give a nicer interface.
> 
>   probeMap = [EmptyProbeMap createBegin: aZone];
>   [probeMap setProbedClass: [self class]];
>   probeMap = [probeMap createEnd];
> 
>   // Add in a bunch of variables, one per simulation parameter
> 
>   [probeMap addProbe: [probeLibrary getProbeForVariable: "worldXSize"
>                                   inClass: [self class]]];
>   [probeMap addProbe: [probeLibrary getProbeForVariable: "worldYSize"
>                                   inClass: [self class]]];
>   [probeMap addProbe: [probeLibrary getProbeForVariable: "numProblems"
>                                   inClass: [self class]]];
>   [probeMap addProbe: [probeLibrary getProbeForVariable: 
> "problemRandomMoveProb"
>                                     inClass: [self class]]];
>   [probeMap addProbe: [probeLibrary getProbeForVariable: "minIdealNumber"
>                                   inClass: [self class]]];
>   [probeMap addProbe: [probeLibrary getProbeForVariable: "maxIdealNumber"
>                                   inClass: [self class]]];
> 
>   // Now install our custom probeMap into the probeLibrary.
> 
>   [probeLibrary setProbeMap: probeMap For: [self class]];
>   
>   return obj;
> }
> 
> // createEnd: we could create some objects here if we knew we needed
> // them. But this method is called before the user is allowed to fill
> // in any customization of the model, so we defer most object creation
> // to later. (In this example, this method does nothing at all and could
> // just be inherited. But it's here to show you a place to customize.)
> 
> -createEnd {
>   return [super createEnd];
> }
> 
> // Now it's time to build the model objects. We use various parameters
> // inside ourselves to choose how to create things.
> 
> -buildObjects {
>   int i;
> 
>   // allow our parent class to build anything.
> 
>   [super buildObjects];
>   
>   // First, set up objects used to represent the environment.
>   // Set up the grid used to represent agent position
> 
>   world = [Grid2d createBegin: [self getZone]];
>   [world setSizeX: worldXSize Y: worldYSize];
>   world = [world createEnd];
> 
>   problemPixmap = [XPixmap createBegin: [self getZone]];
>   [problemPixmap setFile: "problem.xpm"];
>   problemPixmap = [problemPixmap createEnd];
> 
>   // Create a list to keep track of the agents in the model.
> 
>   problemList = [List create: [self getZone]];
>  
>   // Create agents themselves. This is a fairly complex step, as is
>   // appropriate: the agents are essential aspects of the simulation.
> 
>   // First, a quick hack. During creation we might put several agents
>   // in the same square. This is a design flaw, but it's one that's not
>   // fatal, so we ask the world object not to warn us about it. This is
>   // not an example to be emulated :-)
> 
>   [world setOverwriteWarnings: 0];
> 
>   // Now a loop to create a bunch of problems.
> 
>   for (i = 0; i < numProblems; i++) {
>     Problem * problem;
>     int idealNumber;
> 
>     // Choose a random ideal number from the specified
>     // range (model parameters).
> 
>     idealNumber = [uniformIntRand
>                   getIntegerWithMin: minIdealNumber withMax: maxIdealNumber];
> 
>     // Create the problem, set the creation time variables
> 
>     problem = [Problem createBegin: [self getZone]];
>     [problem setWorld: world];
>     problem = [problem createEnd];
> 
>     // Add the problem to the end of the list.
> 
>     [problemList addLast: problem];
> 
>     // Now initialize the rest of the heatbug's state.
> 
>     [problem setPixmap: problemPixmap];
>     [problem setIdealNumber: idealNumber];
> 
>     [problem setX: [uniformIntRand
>                   getIntegerWithMin: 0L
>                   withMax: (worldXSize-1)]  // random position
>           Y: [uniformIntRand getIntegerWithMin: 0L withMax: (worldYSize-1)]];
>   }
> 
>   [world setOverwriteWarnings: 1];              // ok, done cheating.
> 
>   return self;
> }
> 
> // Here is where the model schedule is built, the data structures
> // that define the simulation of time in the mode. The core is an
> // actionGroup that has a list of actions. That's then put in a Schedule.
> 
> -buildActions {
> 
>   [super buildActions];
>   
>   // Create the list of simulation actions. 
> 
>   modelActions = [ActionGroup create: [self getZone]];
>   [modelActions createActionForEach: problemList message: M(step)];  
> 
>   // Then we create a schedule that executes the modelActions. 
>   // This is a simple schedule, with only one action that is just
>   // repeated every time. See mousetraps for more complicated schedules.
>   
>   modelSchedule = [Schedule createBegin: [self getZone]];
>   [modelSchedule setRepeatInterval: 1];
>   modelSchedule = [modelSchedule createEnd];
>   [modelSchedule at: 0 createAction: modelActions];
> 
>   return self;
> }
> 
> // Now set up the model's activation. swarmContext indicates where
> // we're being started in - typically, this model is run as a subswarm
> // of an observer swarm.
> 
> -activateIn: (id) swarmContext {
> 
>   // First, activate ourselves via the superclass activateIn: method.
>   // Just pass along the problemtext: the activity library does the right 
> thing.
> 
>   [super activateIn: swarmContext];
> 
>   // Now activate our own schedule.
> 
>   [modelSchedule activateIn: self];
> 
>   // Finally, return our activity.
> 
>   return [self getActivity];
> }
> 
> @end
> 
> 
> 
> //ProblemObserverSwarm.h
> 
> #import <swarmobject.h>
> #import <space.h>
> #import <activity.h>
> #import <tkobjc.h>
> #import <collections.h>
> #import <simtools.h>
> #import <analysis.h>
> #import "ProblemModel.h"
> 
> @interface ProblemObserver : GUISwarm {
>   int displayFrequency;                                 // one parameter: 
> update freq
> 
>   id displayActions;                            // schedule data structs
>   id displaySchedule;
> 
>   ProblemModel * problemModel;                  // the Swarm we're observing
> 
>   // Lots of display objects. First, widgets
> 
>   XColormap * colormap;                         // allocate colours
>   ZoomRaster * worldRaster;                     // 2d display widget
> 
>   // Now, higher order display and data objects
> 
> 
>   Object2dDisplay * problemDisplay;             // display the problems
> }
> 
> // Methods overriden to make the Swarm.
> 
> +createBegin: (id) aZone;
> -createEnd;
> -buildObjects;
> -buildActions;
> -activateIn: (id) swarmContext;
> 
> @end
> 
> 
> 
> //ProblemObserverSwarm.m
> 
> #import "ProblemObserver.h"
> #import "ProblemModel.h"
> #import <collections.h>
> #import <swarmobject.h>
> #import <analysis.h>
> 
> @implementation ProblemObserver
> 
> // createBegin: here we set up the default observation parameters.
> 
> +createBegin: (id) aZone {
>   ProblemObserver * obj;
>   ProbeMap * probeMap;
>   
>   // Superclass createBegin to allocate ourselves.
> 
>   obj = [super createBegin: aZone];
> 
>   // Fill in the relevant parameters (only one, in this case).
> 
>   obj->displayFrequency = 1;
> 
>   // Also, build a customized probe map. Without a probe map, the default
>   // is to show all variables and messages. Here we choose to
>   // customize the appearance of the probe, give a nicer interface.
> 
>   probeMap = [EmptyProbeMap createBegin: aZone];
>   [probeMap setProbedClass: [self class]];
>   probeMap = [probeMap createEnd];
> 
>   // Add in a bunch of variables, one per simulation parameters
> 
>   [probeMap addProbe: [probeLibrary getProbeForVariable: "displayFrequency"
>                                   inClass: [self class]]];
> 
>   // Now install our custom probeMap into the probeLibrary.
> 
>   [probeLibrary setProbeMap: probeMap For: [self class]];
> 
>   return obj;
> }
> 
> // createEnd: create objects we know we'll need. In this case, none,
> // but you might want to override this.
> 
> -createEnd {
>   return [super createEnd];
> }
> 
> // Create the objects used in the display of the model. This code is
> // fairly complicated because we build a fair number of widgets. It's
> // also a good example of how to use the display code.
> 
> -buildObjects {
>   id modelZone;                                         // zone for model.
>   int i;
> 
>   [super buildObjects];
>   
>   // First, we create the model that we're actually observing. The
>   // model is a subswarm of the observer. We also create the model in
>   // its own zone, so storage is segregated.
> 
>   modelZone = [Zone create: [self getZone]];
>   problemModel = [ProblemModel create: modelZone];
>   
>   // Now create probe objects on the model and ourselves. This gives a
>   // simple user interface to let the user change parameters.
> 
>   [probeDisplayManager createProbeDisplayFor: problemModel];
>   [probeDisplayManager createProbeDisplayFor: self];
> 
>   // Instruct the control panel to wait for a button event: we halt here
>   // until someone hits a control panel button so the user can get a
>   // chance to fill in parameters before the simulation runs
> 
>   [controlPanel setStateStopped];
> 
>   // OK - the user has specified all the parameters for the simulation.
>   // Now we're ready to start.
> 
>   // First, let the model swarm build its objects.
> 
>   [problemModel buildObjects];
> 
>   // Now get down to building our own display objects.
> 
>   // First, create a colormap: this is a global resource, the information
>   // here is used by lots of different objects.
> 
>   colormap = [XColormap create: [self getZone]];
> 
>   // Colours [0,64) are assigned to the range Red [0, 1), for heat display.
> 
>   for (i = 0; i < 64; i++)
>       [colormap setColor: i ToRed: 0 Green: (double)i /63.00 Blue: 0];
> 
>   // Colour 64 is set to green, to display heatbugs
> 
>     [colormap setColor: 64 ToName: "red"];
> 
>   // Colour 65 is set to white, used in this case below on probed heatbug.
> 
>     [colormap setColor: 65 ToName: "white"];
> 
>   // Now go in to the heatbugs in the model and set their colours to green 
> (64)
> 
>   [[problemModel getProblemList] forEach: 
>                        M(setProblemColor:) : (void *) 64];
>   
>   // Next, create a 2d window for display, set its size, zoom factor, title.
> 
>   worldRaster = [ZoomRaster create: [self getZone]];
>   [worldRaster setColormap: colormap];
>   [worldRaster setZoomFactor: 4];
>   [worldRaster setWidth: [[problemModel getWorld] getSizeX]
>              Height: [[problemModel getWorld] getSizeY]];
>   [worldRaster setWindowTitle: "The Neighborhood"];
>   [worldRaster pack];                           // draw the window.
> 
>   // And also create an Object2dDisplay: this object draws heatbugs on
>   // the worldRaster widget for us, and also receives probes.
> 
>   problemDisplay = [Object2dDisplay createBegin: [self getZone]];
>   [problemDisplay setDisplayWidget: worldRaster];
>   [problemDisplay setDiscrete2dToDisplay: [problemModel getWorld]];
>   [problemDisplay setObjectCollection: [problemModel getProblemList]];
>   [problemDisplay setDisplayMessage: M(drawSelfOn:)];   // draw method
>   problemDisplay = [problemDisplay createEnd];
> 
>   // Also, tell the world raster to send mouse clicks to the problemDisplay
>   // this allows the user to right-click on the display to probe the bugs.
> 
>   [worldRaster setButton: ButtonRight Client: problemDisplay Message: 
> M(makeProbeAtX:Y:)];
> 
>   return self;
> }  
> 
> // Create the actions necessary for the simulation. This is where
> // the schedule is built (but not run!)
> 
> -buildActions {
>   [super buildActions];
>   
>   // First, let our model swarm build its own schedule.
> 
>   [problemModel buildActions];
>   
>   // Create an ActionGroup for display: a bunch of things that occur in
>   // a specific order, but at one step of simulation time. Some of these
>   // actions could be executed in parallel, but we don't explicitly
>   // notate that here.
> 
>   displayActions = [ActionGroup create: [self getZone]];
> 
>   // Schedule up the methods to draw the display of the world
> 
>   [displayActions createActionTo: problemDisplay      message: M(display)];
>   [displayActions createActionTo: worldRaster         message: M(drawSelf)];
> 
>   // Schedule the update of the probe displays
> 
>   [displayActions createActionTo: probeDisplayManager message: M(update)];
> 
>   // Finally, schedule an update for the whole user interface code.
>   // This is crucial: without this, no graphics update and the control
>   // panel will be dead. It's best to put it at the end of the display 
> schedule
> 
>   [displayActions createActionTo: controlPanel        message: M(doTkEvents)];
> 
>   // And the display schedule. Note the repeat interval is set from our
>   // own Swarm data structure. Display is frequently the slowest part of a
>   // simulation, so redrawing less frequently can be a help.
> 
>   displaySchedule = [Schedule createBegin: [self getZone]];
>   [displaySchedule setRepeatInterval: displayFrequency]; // note frequency!
>   displaySchedule = [displaySchedule createEnd];
>   [displaySchedule at: 0 createAction: displayActions];
>   
>   return self;
> }  
> 
> // activateIn: - activate the schedules so they're ready to run.
> // The swarmContext argument has to do with what we were activated *in*.
> // Typically the ObserverSwarm is the top-level Swarm, so it's activated
> // in "nil". But other Swarms and Schedules and such will be activated
> // inside of us.
> 
> -activateIn: (id) swarmContext {
> 
>   // First, activate ourselves (just pass along the context).
> 
>   [super activateIn: swarmContext];
> 
>   // Activate the model swarm in ourselves. The model swarm is a
>   // subswarm of the observer swarm.
> 
>   [problemModel activateIn: self];
> 
>   // Now activate our schedule in ourselves. This arranges for the
>   // execution of the schedule we built.
> 
>   [displaySchedule activateIn: self];
>   
>   // Activate returns the swarm activity - the thing that's ready to run.
> 
>   return [self getActivity];
> }
> 
> @end

                  ==================================
   Swarm-Support is for discussion of the technical details of the day
   to day usage of Swarm.  For list administration needs (esp.
   [un]subscribing), please send a message to <address@hidden>
   with "help" in the body of the message.
                  ==================================


reply via email to

[Prev in Thread] Current Thread [Next in Thread]