Re: Objects and classes, try 3

2003-03-10 Thread Graham Barr
On Sun, Mar 09, 2003 at 02:08:02PM -0500, Dan Sugalski wrote:
 At 1:52 PM -0500 3/9/03, Uri Guttman wrote:
DS == Dan Sugalski [EMAIL PROTECTED] writes:
 
 
DS * Objects have properties you can fetch and store by name
DS * Objects have methods you can call
DS * Objects have attributes you can fetch
 
 and store
 
 Well... I'm not sure about that. Classes can store data in object 
 attributes, but there isn't necessarily a public API through the PMC 
 to do this. Basically if you can get to it through a PMC's vtable, it 
 was on the Objects have list. I'm not sure that storing into an 
 attribute should be easily doable from the outside.
 
 Methods have access to an object's internal bits, so the class 
 methods can poke into slots in the attribute array directly, which is 
 probably how they'll work.

Surely thats a high-level restriction that Perl will impose. Why should Parrot
impose that restriction ? Other languages may want to access attributes from
outside the class.

Graham.


Re: Objects and classes, try 3

2003-03-10 Thread Dan Sugalski
At 10:22 AM -0500 3/10/03, Christopher Armstrong wrote:
On Sun, Mar 09, 2003 at 01:07:46PM -0500, Dan Sugalski wrote:

 * Objects have properties you can fetch and store by name
 * Objects have methods you can call
 * Objects have attributes you can fetch
 * You can fetch a hash of all the properties
 * When fetching or storing a generic property, you may call a method
 instead, as methods win
 * You can fetch a method PMC from the object
 * You can fetch the object's Class PMC
 All of these have vtable entries in the PMC: get_prop, set_prop,
 get_attrib, set_attrib, get_prop_hash, get_method, call_method,
 get_class. (Some already have names, I'm doing this from memory)
 No, you can't set a method or the property hash from an object PMC.
 Arguments with good reasons to do so will be cheerfully read and not
 implemented. :)
How about target languages allow you to do this? :) (Python!)
Nope! Python's attributes map to Parrot's properties. I'm going to 
add in a translation matrix/glossary to the PDD when I write it, as I 
keep getting confused as to who calls which thing what. :)

Still, I've given up on enforcing no-outsite-writing to attributes. 
I'm going to add in a set_attrib vtable method, and let 
alternate-object systems have at it.

(And you're right, I was getting interface and implementation sloppy 
before, which is a mistake I'm trying not to make in the actual spec)
--
Dan

--it's like this---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk


Re: Objects and classes, try 3

2003-03-10 Thread Dan Sugalski
At 8:25 AM + 3/10/03, Graham Barr wrote:
On Sun, Mar 09, 2003 at 02:08:02PM -0500, Dan Sugalski wrote:
 At 1:52 PM -0500 3/9/03, Uri Guttman wrote:
DS == Dan Sugalski [EMAIL PROTECTED] writes:
 
 
DS * Objects have properties you can fetch and store by name
DS * Objects have methods you can call
DS * Objects have attributes you can fetch
 
 and store
 Well... I'm not sure about that. Classes can store data in object
 attributes, but there isn't necessarily a public API through the PMC
 to do this. Basically if you can get to it through a PMC's vtable, it
 was on the Objects have list. I'm not sure that storing into an
 attribute should be easily doable from the outside.
 Methods have access to an object's internal bits, so the class
 methods can poke into slots in the attribute array directly, which is
 probably how they'll work.
Surely thats a high-level restriction that Perl will impose. Why should Parrot
impose that restriction ? Other languages may want to access attributes from
outside the class.
The big reason to impose it is because if I do, then parrot doesn't 
need to expose the details of attributes to user code. That seemed to 
make sense at the time, but since we're letting user code fetch 
attributes by name or slot number as it is, I'm not sure that one 
more vtable entry is a problem.

I'll add in update capabilities to the spec.
--
Dan
--it's like this---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk


Re: Objects and classes, try 3

2003-03-10 Thread Christopher Armstrong
On Sun, Mar 09, 2003 at 01:07:46PM -0500, Dan Sugalski wrote:

 * Objects have properties you can fetch and store by name
 * Objects have methods you can call
 * Objects have attributes you can fetch
 * You can fetch a hash of all the properties
 * When fetching or storing a generic property, you may call a method 
 instead, as methods win
 * You can fetch a method PMC from the object
 * You can fetch the object's Class PMC
 
 All of these have vtable entries in the PMC: get_prop, set_prop, 
 get_attrib, set_attrib, get_prop_hash, get_method, call_method, 
 get_class. (Some already have names, I'm doing this from memory)
 
 No, you can't set a method or the property hash from an object PMC. 
 Arguments with good reasons to do so will be cheerfully read and not 
 implemented. :)

How about target languages allow you to do this? :) (Python!)

But otherwise, I like this spec much more than your previous ones. It
seems more interface-oriented than implementation-oriented. That's
crucial for language compatibility, I think. If you stick to an
interface-oriented approach, then it should be no problem for Python,
Perl, Ruby, etc, to implement all of their wacky object semantics
while preventing incompatibility (or even special inter-language glue
code).

-- 
 Twisted | Christopher Armstrong: International Man of Twistery
  Radix  |  Release Manager,  Twisted Project
-+ http://twistedmatrix.com/users/radix.twistd/


Re: Objects and classes, try 3

2003-03-09 Thread Piers Cawley
Dan Sugalski [EMAIL PROTECTED] writes:

 At 6:53 PM + 3/9/03, Piers Cawley wrote:
Dan Sugalski [EMAIL PROTECTED] writes:

  Okay, here's try three. I think I'm about ready to POD this up as a
  formal spec to be assaulted, but this version is more a sketch than
  anything:

[...]

Am I reading it right if I reckon that a Class isa Object? and an
Object hasa Class (assuming that the object is, um, Classy)?

 Pretty much, yeah. I'm not sure if Classes will be objects as such,
 rather than just another Special PMC Thing (like scalars, hashes,
 arrays) but they'll be pretty darned close to objects if they aren't.

For various, nefarious reasons I'd like to be able to manipulate
classes as objects at a language level, even if they aren't objects
down at the Parrot level, but I'll wait for Apo 12 for that one.

-- 
Piers


Re: Objects and classes, try 3

2003-03-09 Thread Uri Guttman
 DS == Dan Sugalski [EMAIL PROTECTED] writes:

   so any class X that inherits from B must also modify the PARENT property
   in B? that sounds like PARENT is a hash of the classes which inherit
   from B.

  DS Yep. Basically if the inheriting class is of a different type, such that
  DS the parent class must be inherited with delegation, then when the parent
  DS object is instantiated it gets the PARENT property on it. Messy in some
  DS ways, but I don't see any way around it.

the use of 'inherit' with delegation bothers me. that assumes (some of)
the method names in the owned object are the same in the owner (parent)
object. 

   how does that handle which methods in the 'owner' object get
   mapped/delegated to which methods in the 'owned' object? damian's
   delegate module has a map for that with owner method names mapping to
   attribute (owned object)/method pairs. not all methods of an owned
   object need to be accessible via the owner's interface. also how do you
   handle multiple owned objects and method mapping?

  DS Ah, this isn't for the Damian We do Interesting Things with delegation
  DS stuff. This mechanism is in specifically to handle inheriting from an
  DS incompatible parent class. Stuff like Damian wants can be handled
  DS completely in user-code, so it should be.

i assume by user code you mean perl6 itself? that can be done just
before method lookup is called but the mapping hash still has to be in
the object/class and private to that. can that be handled at the perl6
level without parrot support?

  DS At some point someone will come up with a clever general way to handle
  DS this, in which case we'll look into rolling it into the base object
  DS system, but for now, in the interests of what simplicity we can muster,
  DS we're going to duck the issue.

it doesn't seem to be too hard. all that is needed is a OWNED/DELEGATED
hash with the method/delegated mappings provided by perl6. then that map
(if it exists) is checked before any other method lookups are done. this
is all i see that is needed to support proper delegation and it is
pretty much what damian's module does now. it can be added later if it
simplifies things now but it doesn't seem that complex or tricky.

uri

-- 
Uri Guttman  --  [EMAIL PROTECTED]   http://www.stemsystems.com
- Stem and Perl Development, Systems Architecture, Design and Coding 
Search or Offer Perl Jobs    http://jobs.perl.org
Damian Conway Perl Classes - January 2003 -- http://www.stemsystems.com/class


Re: Objects and classes, try 3

2003-03-09 Thread Dan Sugalski
At 8:01 PM + 3/9/03, Piers Cawley wrote:
Dan Sugalski [EMAIL PROTECTED] writes:

 At 6:53 PM + 3/9/03, Piers Cawley wrote:
Dan Sugalski [EMAIL PROTECTED] writes:

  Okay, here's try three. I think I'm about ready to POD this up as a
  formal spec to be assaulted, but this version is more a sketch than
  anything:
[...]

Am I reading it right if I reckon that a Class isa Object? and an
Object hasa Class (assuming that the object is, um, Classy)?
 Pretty much, yeah. I'm not sure if Classes will be objects as such,
 rather than just another Special PMC Thing (like scalars, hashes,
 arrays) but they'll be pretty darned close to objects if they aren't.
For various, nefarious reasons I'd like to be able to manipulate
classes as objects at a language level, even if they aren't objects
down at the Parrot level, but I'll wait for Apo 12 for that one.
I think Larry's planning on that, which is fine, and I'd as soon 
allow it in at least some form, because it seems really useful, if a 
bit evil.
--
Dan

--it's like this---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk


Re: Objects and classes, try 3

2003-03-09 Thread Dan Sugalski
At 3:05 PM -0500 3/9/03, Uri Guttman wrote:
  DS == Dan Sugalski [EMAIL PROTECTED] writes:

   so any class X that inherits from B must also modify the PARENT property
   in B? that sounds like PARENT is a hash of the classes which inherit
   from B.
  DS Yep. Basically if the inheriting class is of a different type, such that
  DS the parent class must be inherited with delegation, then when the parent
  DS object is instantiated it gets the PARENT property on it. Messy in some
  DS ways, but I don't see any way around it.
the use of 'inherit' with delegation bothers me. that assumes (some of)
the method names in the owned object are the same in the owner (parent)
object.
Yup. What I'm talking about here is delegation to implement 
inheritance, in those cases where the parent and child classes are 
structurally incompatible.

   how does that handle which methods in the 'owner' object get
   mapped/delegated to which methods in the 'owned' object? damian's
   delegate module has a map for that with owner method names mapping to
   attribute (owned object)/method pairs. not all methods of an owned
   object need to be accessible via the owner's interface. also how do you
   handle multiple owned objects and method mapping?
  DS Ah, this isn't for the Damian We do Interesting Things with delegation
  DS stuff. This mechanism is in specifically to handle inheriting from an
  DS incompatible parent class. Stuff like Damian wants can be handled
  DS completely in user-code, so it should be.
i assume by user code you mean perl6 itself?
Yep.

that can be done just
before method lookup is called but the mapping hash still has to be in
the object/class and private to that. can that be handled at the perl6
level without parrot support?
I don't plan on adding any special support for the fancy delegation 
tricks Damian plays. I don't think there's any real need--the 
standard AUTILOAD and shim creation tricks he plays to get it working 
will work just fine, so there's not much need for anything else.

  DS At some point someone will come up with a clever general way to handle
  DS this, in which case we'll look into rolling it into the base object
  DS system, but for now, in the interests of what simplicity we can muster,
  DS we're going to duck the issue.
it doesn't seem to be too hard. all that is needed is a OWNED/DELEGATED
hash with the method/delegated mappings provided by perl6. then that map
(if it exists) is checked before any other method lookups are done. this
is all i see that is needed to support proper delegation and it is
pretty much what damian's module does now. it can be added later if it
simplifies things now but it doesn't seem that complex or tricky.
I don't think the extra support will be difficult, I just think it's 
stuff we don't need to implement to get our required functionality. I 
also think it can be done entirely without extra engine support, so 
as such I'd as soon not do anything about it for now. We've more than 
enough to do as it is. :)
--
Dan

--it's like this---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk


Objects and classes, try 3

2003-03-09 Thread Dan Sugalski
Okay, here's try three. I think I'm about ready to POD this up as a 
formal spec to be assaulted, but this version is more a sketch than 
anything:

Objects
===
* Objects have properties you can fetch and store by name
* Objects have methods you can call
* Objects have attributes you can fetch
* You can fetch a hash of all the properties
* When fetching or storing a generic property, you may call a method 
instead, as methods win
* You can fetch a method PMC from the object
* You can fetch the object's Class PMC

All of these have vtable entries in the PMC: get_prop, set_prop, 
get_attrib, set_attrib, get_prop_hash, get_method, call_method, 
get_class. (Some already have names, I'm doing this from memory)

No, you can't set a method or the property hash from an object PMC. 
Arguments with good reasons to do so will be cheerfully read and not 
implemented. :)

PMCs are responsible for making sure the get/set property stuff calls 
methods if that should happen per the PMC's owning language spec.

If the property hash should call methods when things are fetched from 
it (because there are override fetch methods or something) then the 
PMC is responsible for returning a hash PMC with appropriate active 
get/set methods attached to it.

Objects may actually be composite objects, if we're doing inheritance 
via delegation, for when we inherit from a class of a different type. 
In that case the delegated object has a property on it that refers to 
the 'master' object that represents the ultimate child class' object. 
This is done with a PARENT property on the

Note that objects do *not* have to have classes. Variables don't even 
have to *be* objects, as such--plain integers can implement all this 
stuff if they want. We're OO-fuzzy here.

Classes
===
Classes are indirectly responsible for how objects behave, as the 
class constructs the initial vtable that gets assigned to each 
object. (Well, the PMC class, and language level classes will all 
have a custom generated PMC class for them) The only thing actually 
semi-required of classes is a set of metadata. It's semi-required in 
that any class that uses the metadata *must* use it in the way we 
prescribe. Anyone's free to do things differently, in which case it's 
just a matter of implementing the right vtable code and suchlike 
things. Doable, if not actually simple.

Parrot's base class mechanism support multiple inheritance, delegated 
inheritance, and inherited interfaces. They correspond, more or less, 
to is, has and does, and that's what we're going to refer to 
them as. We are class-based, since that's what perl 6, python, and 
ruby all do. Some of the other object systems are interesting, but 
we're not going to bother with them here. Not our focus.

Each class is represented by a PMC with an is, and does property, 
which are arrays of parent classes and parent interfaces, 
respectively. The default method dispatch vtable function should 
respect both the is and does list--personally I'm thinking we should 
pre-populate the method table for a class since we're going to do 
notifications, but we can defer that until later.

Each class has the following semi-required properties (The names aren't fixed):

* does - Array of immediate parent interfaces
* is - Array of immediate parent classes
* needs - A count of the attributes for this class (class only, not 
parent classes)
* attributes - an array of attribute names for this class (not parent 
classes, just this class)
* object_style - What type of object this is. 0 = no object, 1 = 
parrot base object, 2 = delegated object
* core_functions - An array of the core functions for the class. 
We'll get to those in a moment.

Core Functions
==
These are in the core_functions property array, and are considered 
part of the base parrot class/object mechanism. They're here since we 
may need to do something fancier than a plain 
most-derived-class-method call.

* allocate - Called when we need to create a new object. Must return a PMC
* initialize - Called when we need to initialize the object that 
allocate returned

Destruction is part of the vtable, so classes should just fill that 
in in their initialization code.

Method Dispatch
===
The engine will have a function to determine the closest method or 
sub in a tree, given a signature. We walk the tree of classes based 
on the metainformation and do our best to find the right method. (No, 
we've not talked about method metadata. Assume we have some)

The base method dispatch looks for actual sub/methods, then AUTOLOAD, 
then multimethod dispatch. We do *not* do AUTOLOAD for more 'special' 
methods (no AUTOLOADed DESTROY methods, for example) so if a language 
requires them it should instantiate an empty method (one with a 
signature but no code) as when we call those we do invoke the class' 
autoloading mechanism to find the body.
--
Dan

--it's like 

Re: Objects and classes, try 3

2003-03-09 Thread Uri Guttman
 DS == Dan Sugalski [EMAIL PROTECTED] writes:


  DS * Objects have properties you can fetch and store by name
  DS * Objects have methods you can call
  DS * Objects have attributes you can fetch

and store

  DS * You can fetch a hash of all the properties
  DS * When fetching or storing a generic property, you may call a method
  DS   instead, as methods win

what about methods overriding attributes? or are attribute accessors
just methods?


  DS Objects may actually be composite objects, if we're doing inheritance
  DS via delegation, for when we inherit from a class of a different type. In
  DS that case the delegated object has a property on it that refers to the
  DS 'master' object that represents the ultimate child class' object. This
  DS is done with a PARENT property on the

on the what?

it would be helpful to clarify which direction you mean with
parent/child with regard to delegation. i take it the parent object gets
the original method call and it delegates it to the child object that
the parent owns. i use 'own' (others say 'has') for the delegation
relationship and i mean the parent owns the child which will get the
delegated call. note that a parent could own multiple children of the
same name and delegate different parent methods to different
children. 'has' doesn't cover that case as well as own. minor semantic
difference but worth mentioning.

  DS Each class is represented by a PMC with an is, and does property,
  DS which are arrays of parent classes and parent interfaces,
  DS respectively. The default method dispatch vtable function should respect
  DS both the is and does list--personally I'm thinking we should
  DS pre-populate the method table for a class since we're going to do
  DS notifications, but we can defer that until later.

what about 'has'?

uri

-- 
Uri Guttman  --  [EMAIL PROTECTED]   http://www.stemsystems.com
- Stem and Perl Development, Systems Architecture, Design and Coding 
Search or Offer Perl Jobs    http://jobs.perl.org
Damian Conway Perl Classes - January 2003 -- http://www.stemsystems.com/class


Re: Objects and classes, try 3

2003-03-09 Thread Piers Cawley
Dan Sugalski [EMAIL PROTECTED] writes:

 Okay, here's try three. I think I'm about ready to POD this up as a
 formal spec to be assaulted, but this version is more a sketch than
 anything:

[...]

Am I reading it right if I reckon that a Class isa Object? and an
Object hasa Class (assuming that the object is, um, Classy)?

-- 
Piers


Re: Objects and classes, try 3

2003-03-09 Thread Dan Sugalski
At 6:53 PM + 3/9/03, Piers Cawley wrote:
Dan Sugalski [EMAIL PROTECTED] writes:

 Okay, here's try three. I think I'm about ready to POD this up as a
 formal spec to be assaulted, but this version is more a sketch than
 anything:
[...]

Am I reading it right if I reckon that a Class isa Object? and an
Object hasa Class (assuming that the object is, um, Classy)?
Pretty much, yeah. I'm not sure if Classes will be objects as such, 
rather than just another Special PMC Thing (like scalars, hashes, 
arrays) but they'll be pretty darned close to objects if they aren't.
--
Dan

--it's like this---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk


Re: Objects and classes, try 3

2003-03-09 Thread Dan Sugalski
At 1:52 PM -0500 3/9/03, Uri Guttman wrote:
  DS == Dan Sugalski [EMAIL PROTECTED] writes:

  DS * Objects have properties you can fetch and store by name
  DS * Objects have methods you can call
  DS * Objects have attributes you can fetch
and store
Well... I'm not sure about that. Classes can store data in object 
attributes, but there isn't necessarily a public API through the PMC 
to do this. Basically if you can get to it through a PMC's vtable, it 
was on the Objects have list. I'm not sure that storing into an 
attribute should be easily doable from the outside.

Methods have access to an object's internal bits, so the class 
methods can poke into slots in the attribute array directly, which is 
probably how they'll work.

  DS * You can fetch a hash of all the properties
  DS * When fetching or storing a generic property, you may call a method
  DS   instead, as methods win
what about methods overriding attributes? or are attribute accessors
just methods?
Attribute accessors are methods. If an object wants accessors, it 
exports lvalue  methods (potentially--they don't strictly have to be 
lvalue if it's read-only) for them.

  DS Objects may actually be composite objects, if we're doing inheritance
  DS via delegation, for when we inherit from a class of a different type. In
  DS that case the delegated object has a property on it that refers to the
  DS 'master' object that represents the ultimate child class' object. This
  DS is done with a PARENT property on the
on the what?
The delegated object. D'oh!

So if class A isa B, and B is a perl 5 hash-object-thingie, the 
object that B creates would have the PARENT property stuck on it, 
pointing ot the A object. That way B can make method calls on its 
object the right way. (If B couldn't get back to the containing 
object transparently we'd trim off a lot of the inheritance tree and 
we don't want that)

it would be helpful to clarify which direction you mean with
parent/child with regard to delegation. i take it the parent object gets
the original method call and it delegates it to the child object that
the parent owns. i use 'own' (others say 'has') for the delegation
relationship and i mean the parent owns the child which will get the
delegated call. note that a parent could own multiple children of the
same name and delegate different parent methods to different
children. 'has' doesn't cover that case as well as own. minor semantic
difference but worth mentioning.
Sorry. Parent == derived class, child == parent class. Bad choice of 
words on my part.

  DS Each class is represented by a PMC with an is, and does property,
  DS which are arrays of parent classes and parent interfaces,
  DS respectively. The default method dispatch vtable function should respect
  DS both the is and does list--personally I'm thinking we should
  DS pre-populate the method table for a class since we're going to do
  DS notifications, but we can defer that until later.
what about 'has'?
Don't need it. The object the class 'has' is stored in an attribute 
slot, and the class is in the is array, since it really 'is' that 
foreign class, albeit with some magic to make it work. (The parent 
property and such)
--
Dan

--it's like this---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk


Re: Objects and classes, try 3

2003-03-09 Thread Uri Guttman
 DS == Dan Sugalski [EMAIL PROTECTED] writes:

  DS At 1:52 PM -0500 3/9/03, Uri Guttman wrote:

  DS is done with a PARENT property on the
   
   on the what?

  DS The delegated object. D'oh!

  DS So if class A isa B, and B is a perl 5 hash-object-thingie, the object
  DS that B creates would have the PARENT property stuck on it, pointing ot
  DS the A object. That way B can make method calls on its object the right
  DS way. (If B couldn't get back to the containing object transparently we'd
  DS trim off a lot of the inheritance tree and we don't want that)

so any class X that inherits from B must also modify the PARENT property
in B? that sounds like PARENT is a hash of the classes which inherit
from B.

i hate all the variant OO names, parent/super/etc. so damned
confusing. maybe we should have a special parrot OO section in the
glossary

   it would be helpful to clarify which direction you mean with
   parent/child with regard to delegation. i take it the parent object gets
   the original method call and it delegates it to the child object that
   the parent owns. i use 'own' (others say 'has') for the delegation
   relationship and i mean the parent owns the child which will get the
   delegated call. note that a parent could own multiple children of the
   same name and delegate different parent methods to different
   children. 'has' doesn't cover that case as well as own. minor semantic
   difference but worth mentioning.

  DS Sorry. Parent == derived class, child == parent class. Bad choice of
  DS words on my part.

so please resend that out soon (try 4) with the edits.

ditto on the glossary note :)

  DS Each class is represented by a PMC with an is, and does property,
  DS which are arrays of parent classes and parent interfaces,
  DS respectively. The default method dispatch vtable function should respect
  DS both the is and does list--personally I'm thinking we should
  DS pre-populate the method table for a class since we're going to do
  DS notifications, but we can defer that until later.
   
   what about 'has'?

  DS Don't need it. The object the class 'has' is stored in an attribute
  DS slot, and the class is in the is array, since it really 'is' that
  DS foreign class, albeit with some magic to make it work. (The parent
  DS property and such)

how does that handle which methods in the 'owner' object get
mapped/delegated to which methods in the 'owned' object? damian's
delegate module has a map for that with owner method names mapping to
attribute (owned object)/method pairs. not all methods of an owned
object need to be accessible via the owner's interface. also how do you
handle multiple owned objects and method mapping?

i happen to like owned/has more than most and use it quite a bit more
than ISA these days. i would like to see a clean mapping spec like the
delegate module has.

uri

-- 
Uri Guttman  --  [EMAIL PROTECTED]   http://www.stemsystems.com
- Stem and Perl Development, Systems Architecture, Design and Coding 
Search or Offer Perl Jobs    http://jobs.perl.org
Damian Conway Perl Classes - January 2003 -- http://www.stemsystems.com/class