Difference between Java iterator and iterator in Gang of Four

Discussion in 'Java' started by Hendrik Maryns, Dec 19, 2005.

  1. Hi,

    I just read through the Design Patterns book of Gamma et al., also known
    as the GoF, and noticed that they define a method Start in their
    iterator, which does nothing but set the index to zero. I would find
    this possibility rather useful, as I want to recycle some iterators.
    Right now I have to recreate them at the end of the loop every time.
    This seems rather inefficient to me.

    Why didnĀ“t Sun include this method in the Iterator interface? Do they
    have good reasons for this?

    H.
    --
    Hendrik Maryns

    ==================
    www.lieverleven.be
    http://aouw.org
    Hendrik Maryns, Dec 19, 2005
    #1
    1. Advertising

  2. Hendrik Maryns

    Chris Smith Guest

    Hendrik Maryns <> wrote:
    > I just read through the Design Patterns book of Gamma et al., also known
    > as the GoF, and noticed that they define a method Start in their
    > iterator, which does nothing but set the index to zero. I would find
    > this possibility rather useful, as I want to recycle some iterators.
    > Right now I have to recreate them at the end of the loop every time.
    > This seems rather inefficient to me.
    >
    > Why didn=3Ft Sun include this method in the Iterator interface? Do they
    > have good reasons for this?


    If this seems rather inefficient, I'd suggest you re-evaluate your ideas
    of performance. It could be nice if iterators had some kind of a reset
    method... but recreating an iterator from an existing collection is
    hardly expensive.

    My best guess as to why it wasn't included is that Iterator is intended
    for any Collection... not necessarily one that's in memory all the time
    or that even has a defined order; I can conceive of such a structure for
    which there is not easy way to start over without performing a
    significant amount of work... or for which it's not even possible at
    all. (Of course, in the world of optional methods -- the Collections
    API -- it almost seems unusual that something would be omitted just
    because it may not apply.)

    --
    www.designacourse.com
    The Easiest Way To Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Dec 19, 2005
    #2
    1. Advertising

  3. Hendrik Maryns

    VisionSet Guest

    "Hendrik Maryns" <> wrote in message
    news:do6os9$pa0$-tuebingen.de...

    > I want to recycle some iterators.
    >Right now I have to recreate them at the end of the loop every time.
    >This seems rather inefficient to me.


    An Iterator is extremely light weight, it is nothing more than a reference
    structure for pointing at the original collection, but I guess you know that
    if you've read GOF.
    Take a look at the sun source (eg AbstractList) for their various
    implementations they have just a couple of int index/cursor attributes.
    It is very normal to create them on any whim. It is the choice method to
    access collections, so much so there's now the for/each language
    augmentation to support it.

    --
    Mike W
    VisionSet, Dec 19, 2005
    #3
  4. Hendrik Maryns

    Guest

    It's better to keep the interface as minimal as possible, to keep the
    limitations on where it can be used to a minimum, and to keep the
    effort required in implementing it to a minimum.

    Creating another Iterator is very cheap, for all collections I've known
    about.

    Use a profiler to examine performance, don't guess.

    Oh, when you reimplement List, feel free to make your own
    RestartableIterator for these purposes.
    , Dec 19, 2005
    #4
  5. Hendrik Maryns

    Googmeister Guest

    Chris Smith wrote:
    > Hendrik Maryns <> wrote:
    > > I see that you can conceive structures which are hard to restart
    > > iterating /in the same order/, but I merely want the option to say:
    > > start your iteration again, for example, in (Hash)Set, there is no order
    > > guarantee at all. But as indeed they are only a lightweight wrapper of
    > > indexes, and with what I read about the differences in object creating
    > > between Java and C++, I can see why they left this out.

    >
    > See Roedy's reply. It may be that the iteration can't be repeated at
    > all, in any order. (Again, there's no consistent justification, though,
    > for leaving this out while including other optional operations... except
    > that someone didn't think this was as useful.)


    Yes. I don't understand why remove() is part of the Iterator
    interface, while being optional. Wouldn't it be better design
    to have a separate interface, say, RemovableIterator, for
    those times when you also want to support remove()?
    Moveover, the remove() method mutates the underlying
    collection, whereas the simpler interface without remove()
    could guarantee never to change it.

    Any insight into why remove() is part of Iterator?
    Googmeister, Dec 20, 2005
    #5
  6. Hendrik Maryns

    Roedy Green Guest

    On 19 Dec 2005 17:46:54 -0800, "Googmeister" <>
    wrote, quoted or indirectly quoted someone who said :

    >Yes. I don't understand why remove() is part of the Iterator
    >interface, while being optional. Wouldn't it be better design
    >to have a separate interface, say, RemovableIterator, for
    >those times when you also want to support remove()?


    I agree. I think that was just an error. They did not realise until it
    was too late that forcing you to support remove was too onerous and
    the code would likely never be used.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Java custom programming, consulting and coaching.
    Roedy Green, Dec 20, 2005
    #6
  7. Hendrik Maryns

    Chris Smith Guest

    Roedy Green <> wrote:
    > I agree. I think that was just an error. They did not realise until it
    > was too late that forcing you to support remove was too onerous and
    > the code would likely never be used.


    Au contraire. From the beginning, it was very carefully considered and
    decided that remove() should be provided and made into an optional
    operation. Optional operations were quite deliberately designed into
    the collections API. The goal was to reduce the number of public
    interfaces. Careful before you dismiss this. Mutable versus immutable
    is only one possible distinction. Arrays.asList creates a List
    implementation that supports only that mutation which does not change
    the length. The danger was that different operations might be legal in
    different contexts, and there might be a combinatoric explosion of
    superinterfaces if the API walked that road.

    Whether this was a good idea or not is another matter. I believe that
    it was not. However, it was a deliberate decision made in response to
    real challenges. It was a conscious decision for simplicity over
    safety.

    (How that decision meshes with the later decision to add generics to the
    type system is a question for a different thread. Clearly, these value
    judgements are made differently by different people at Sun.)

    --
    www.designacourse.com
    The Easiest Way To Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Dec 20, 2005
    #7
  8. Hendrik Maryns

    Roedy Green Guest

    On Mon, 19 Dec 2005 23:18:19 -0700, Chris Smith <>
    wrote, quoted or indirectly quoted someone who said :

    >Au contraire. From the beginning, it was very carefully considered and
    >decided that remove() should be provided and made into an optional
    >operation.


    How do you know this?
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Java custom programming, consulting and coaching.
    Roedy Green, Dec 20, 2005
    #8
  9. Hendrik Maryns

    Chris Smith Guest

    Roedy Green <> wrote:
    > On Mon, 19 Dec 2005 23:18:19 -0700, Chris Smith <>
    > wrote, quoted or indirectly quoted someone who said :
    >
    > >Au contraire. From the beginning, it was very carefully considered and
    > >decided that remove() should be provided and made into an optional
    > >operation.

    >
    > How do you know this?


    Mostly I deduced this from common sense. Though I hardly think Sun is
    immune from making mistakes, the level of mistake which you suggest --
    to forget about the possibility of immutable collections when designing
    a general-purpose collections API -- would be phenomenally negligent and
    require that they employ only complete morons. That's clearly not true.

    Incidentally, Google confirms my thoughts on the matter. This
    information is out there for the finding. See, for example:

    http://java.sun.com/j2se/1.4.2/docs/guide/collections/designfaq.html

    Of course, no one wrote that text to defend against this specific
    outrageous charge of idiocy, but "We would have supported it if we
    believed it were feasible" implies that, in fact, they thought about it
    and decided it wasn't feasible... not that they forgot and then never
    bothered to fix it.

    You'll also probably recall that the design team at Sun went out of
    their way to ask Doug Lea for input based on the experience he had with
    his then-popular third-party collections framework. Since Doug's
    framework did provide compile-time checking for immutable iterators and
    collections via interface hierarchies, it's doubly unlikely that the
    idea never occurred to Sun's design team even while they read his
    existing code to implement it.

    --
    www.designacourse.com
    The Easiest Way To Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Dec 20, 2005
    #9
  10. Hendrik Maryns sez:
    [ iterators ]
    > start your iteration again, for example, in (Hash)Set, there is no order
    > guarantee at all. But as indeed they are only a lightweight wrapper of
    > indexes, and with what I read about the differences in object creating
    > between Java and C++, I can see why they left this out.


    Errm, they aren't lightweight wrappers for indexes. Recall that
    Java has no separate RandomAccess and SequentialAccess lists,
    there's only one List and it's implicitly sequential access.

    Which means that rewinding an iterator is O(n) -- creating a
    new one will be much faster in most cases.

    Also, every index-based access is O(n), giving you O(n) for
    for( Iterator i = l.iterator(); i.hasNext(); )
    e = i.next();
    and O(n^2) for
    for( int i = 0; i < l.size(); i++ )
    e = l.get( i );

    What's beyond me is why they didn't make Iterator.next()
    return a boolean or void, and Iterator.get() for getting
    to the element: either
    while( i.next() )
    or
    for( Iterator i = l.iterator(); i.hasNext(); i.next() )
    would be much better than what we have now.

    Dima
    --
    Sufficiently advanced incompetence is indistinguishable from malice.
    Dimitri Maziuk, Dec 20, 2005
    #10
  11. Hendrik Maryns

    Eric Sosman Guest

    Dimitri Maziuk wrote On 12/20/05 12:20,:
    > Hendrik Maryns sez:
    > [ iterators ]
    >
    >>start your iteration again, for example, in (Hash)Set, there is no order
    >>guarantee at all. But as indeed they are only a lightweight wrapper of
    >>indexes, and with what I read about the differences in object creating
    >>between Java and C++, I can see why they left this out.

    >
    >
    > Errm, they aren't lightweight wrappers for indexes. Recall that
    > Java has no separate RandomAccess and SequentialAccess lists,
    > there's only one List and it's implicitly sequential access.


    There is only one java.util.List, but there's no implication
    of an access pattern. Various methods of List take a position
    argument, and there is no requirement or even suggestion that
    successive calls to the methods should use adjacent indices.

    True, some particular implementations of List cannot provide
    efficient random access -- but that's not a characteristic of
    List, but of (for example) LinkedList. Implementations like
    ArrayList most definitely do support efficient random access.

    > Which means that rewinding an iterator is O(n) -- creating a
    > new one will be much faster in most cases.


    Even a half-clever programmer can do better than that. If
    there's an efficient way to start a brand-new Iterator at the
    beginning of the List, a hypothetical Iterator.rewind() method
    could use it.

    > Also, every index-based access is O(n), giving you O(n) for
    > for( Iterator i = l.iterator(); i.hasNext(); )
    > e = i.next();
    > and O(n^2) for
    > for( int i = 0; i < l.size(); i++ )
    > e = l.get( i );


    True for LinkedList, but not true for ArrayList or Vector.

    > What's beyond me is why they didn't make Iterator.next()
    > return a boolean or void, and Iterator.get() for getting
    > to the element:


    Ah, but "they" did exactly what you ask! They used
    different names: hasNext() for your next() and next() for
    your get(), but the same[*] functionality is provided.
    Is it just the choice of names that bothers you?

    [*] "The same" for "return a boolean." I confess I
    do not understand what you mean by "return a [...] void,"
    since the only use of `void' in Java is to indicate that
    a method returns nothing at all, not ever.

    > either
    > while( i.next() )
    > or
    > for( Iterator i = l.iterator(); i.hasNext(); i.next() )
    > would be much better than what we have now.


    The first is "what we have now," with a change of name.
    The second is *exactly* "what we have how," so I don't see
    how it "would be much better" than what it already is ...?

    --
    Eric Sosman, Dec 20, 2005
    #11
  12. Dimitri Maziuk wrote:
    >
    > What's beyond me is why they didn't make Iterator.next()
    > return a boolean or void, and Iterator.get() for getting
    > to the element: either
    > while( i.next() )
    > or
    > for( Iterator i = l.iterator(); i.hasNext(); i.next() )
    > would be much better than what we have now.


    Quite. Try writing an iterator filter with strong exception guarantees.
    It ain't pretty. You can't quite do it if removes are permitted.

    Tom Hawtin
    --
    Unemployed English Java programmer
    http://jroller.com/page/tackline/
    Thomas Hawtin, Dec 20, 2005
    #12
  13. Googmeister wrote:
    >
    > Yes. I don't understand why remove() is part of the Iterator
    > interface, while being optional. Wouldn't it be better design
    > to have a separate interface, say, RemovableIterator, for
    > those times when you also want to support remove()?
    > Moveover, the remove() method mutates the underlying
    > collection, whereas the simpler interface without remove()
    > could guarantee never to change it.


    Alpha versions of 1.5 had a SimpleIterator (or ReadOnlyIterator).
    Iterator extended SimpleIterator. Iterable.iterator returned an
    SimpleIterator. As now, Collection extended Iterable.

    Unfortunately having bridging botched by javac rather than implemented
    by the JVM gives slightly different semantics. (In class files, methods
    override if name, parameters and return type match, and the overridden
    method is accessible. Bridge methods override the old method, forwarding
    to the new, narrower typed method.) Old classes directly implementing
    Collection did not have the bridge method, so would throw an
    AbstractMethodError if used through the Iterable interface (e.g. in the
    enhanced for loop).

    Tom Hawtin
    --
    Unemployed English Java programmer
    http://jroller.com/page/tackline/
    Thomas Hawtin, Dec 20, 2005
    #13
  14. Eric Sosman sez:
    >
    >
    > Dimitri Maziuk wrote On 12/20/05 12:20,:

    ....
    > There is only one java.util.List, but there's no implication
    > of an access pattern. Various methods of List take a position
    > argument, and there is no requirement or even suggestion that
    > successive calls to the methods should use adjacent indices.


    RTF Javadoc for java.util.List, spec. where it says

    "Note that these operations may execute in time proportional to
    the index value for some implementations (the LinkedList class,
    for example). Thus, iterating over the elements in a list is
    typically preferable to indexing through it if the caller does not
    know the implementation."

    > True, some particular implementations of List cannot provide
    > efficient random access -- but that's not a characteristic of
    > List, but of (for example) LinkedList. Implementations like
    > ArrayList most definitely do support efficient random access.


    Again, RTFM. Iterator is part of Collection that does not
    guarantee anything, esp. wrt. underlying storage -- so there *is*
    no guarantee of efficient random access. Cf.
    java.util.Iterator<foo>
    Vector::iterator<foo>
    -- the latter form is "iterator over random access container",
    the former is "iterator over any collection".

    Besides, it's not "some particular implementations", it's 50%
    of existing implementations of List that don't provide efficient
    random access.

    > Even a half-clever programmer can do better than that. If
    > there's an efficient way to start a brand-new Iterator at the
    > beginning of the List, a hypothetical Iterator.rewind() method
    > could use it.


    Sure, if it could repoint "this" to the brand-new iterator.
    ....

    > [*] "The same" for "return a boolean." I confess I
    > do not understand what you mean by "return a [...] void,"
    > since the only use of `void' in Java is to indicate that
    > a method returns nothing at all, not ever.


    You don't seem to understand much, do you? Cf.

    while( i.hasNext() ) {
    name = i.next().getName();
    num = i.next().getNumber();
    }

    // boolean next()
    while( i.next() ) {
    name = i.get().getName();
    num = i.get().getNumber();
    }

    // void next()
    for( i = l.iterator(); i.hasNext(); i.next() ) {
    name = i.get().getName();
    num = i.get().getNumber();
    }

    RTF JLS # 8.4 where it says "void" is a method result type.

    Dima
    --
    We're part of that admittedly-too-small group that is trying to save the
    human race from itself. With any luck, we'll fail abjectly and the
    cockroaches will win out.
    -- Mike Andrews
    Dimitri Maziuk, Dec 21, 2005
    #14
  15. Hendrik Maryns

    Eric Sosman Guest

    Dimitri Maziuk wrote On 12/20/05 19:07,:
    > Eric Sosman sez:
    >
    >>
    >>Dimitri Maziuk wrote On 12/20/05 12:20,:

    >
    > ...
    >
    >> There is only one java.util.List, but there's no implication
    >>of an access pattern. Various methods of List take a position
    >>argument, and there is no requirement or even suggestion that
    >>successive calls to the methods should use adjacent indices.

    >
    > RTF Javadoc for java.util.List, spec. where it says
    >
    > "Note that these operations may execute in time proportional to
    > the index value for some implementations (the LinkedList class,
    > for example). Thus, iterating over the elements in a list is
    > typically preferable to indexing through it if the caller does not
    > know the implementation."


    I draw your attention to the word "may" and to the
    phrase "some implementations." In your earlier posting
    you stated as fact that every List required O(n) time to
    access the n'th element. This is true only of some List
    implementations, definitely not of all.

    >> True, some particular implementations of List cannot provide
    >>efficient random access -- but that's not a characteristic of
    >>List, but of (for example) LinkedList. Implementations like
    >>ArrayList most definitely do support efficient random access.

    >
    > Again, RTFM. Iterator is part of Collection that does not
    > guarantee anything, esp. wrt. underlying storage -- so there *is*
    > no guarantee of efficient random access. Cf.
    > java.util.Iterator<foo>
    > Vector::iterator<foo>
    > -- the latter form is "iterator over random access container",
    > the former is "iterator over any collection".


    Iterator has nothing to do with random access, and
    Iterator is not "part of Collection." There seems to be
    a communication problem here.

    > Besides, it's not "some particular implementations", it's 50%
    > of existing implementations of List that don't provide efficient
    > random access.
    >
    >> Even a half-clever programmer can do better than that. If
    >>there's an efficient way to start a brand-new Iterator at the
    >>beginning of the List, a hypothetical Iterator.rewind() method
    >>could use it.

    >
    > Sure, if it could repoint "this" to the brand-new iterator.
    > ...


    No such magic (and it would indeed need to be magical)
    is needed. My claim is that if List.iterator() has an
    efficient way to initialize a new Iterator properly, then
    the same initialization technique is available to the
    hypothetical Iterator.rewind().

    >> [*] "The same" for "return a boolean." I confess I
    >>do not understand what you mean by "return a [...] void,"
    >>since the only use of `void' in Java is to indicate that
    >>a method returns nothing at all, not ever.

    >
    > You don't seem to understand much, do you? Cf.


    Was that called for?

    > while( i.hasNext() ) {
    > name = i.next().getName();
    > num = i.next().getNumber();
    > }
    >
    > // boolean next()
    > while( i.next() ) {
    > name = i.get().getName();
    > num = i.get().getNumber();
    > }
    >
    > // void next()
    > for( i = l.iterator(); i.hasNext(); i.next() ) {
    > name = i.get().getName();
    > num = i.get().getNumber();
    > }


    Aha! Now I see what you were after; it certainly wasn't
    apparent in your earlier posting. You want a get() method
    that does not advance the "current position" of the Iterator.
    I'm not sure why you want such a thing, but if you really
    want it you can easily wrap the Iterator in a helper class.

    > RTF JLS # 8.4 where it says "void" is a method result type.


    I'm aware that `void' is a method result type, but you
    expressed a desire for Iterator.next to "return a boolean
    or void." Not even a `void' method can "return a void."

    --
    Eric Sosman, Dec 21, 2005
    #15
  16. Eric Sosman sez:
    >
    >
    > Dimitri Maziuk wrote On 12/20/05 19:07,:

    ....
    >> "Note that these operations may execute in time proportional to
    >> the index value for some implementations (the LinkedList class,
    >> for example). Thus, iterating over the elements in a list is
    >> typically preferable to indexing through it if the caller does not
    >> know the implementation."


    I love how they phrased it: "some implementations". Until
    they come up with quantum subspace memory, there's only
    two and half of them is sequential access.

    > I draw your attention to the word "may" and to the
    > phrase "some implementations." In your earlier posting
    > you stated as fact that every List required O(n) time to
    > access the n'th element. This is true only of some List
    > implementations, definitely not of all.


    I draw you attention to "does not know the implementation".
    If all you have is "a List" then it's O(n). Similarly, if
    all you have is "a Collection", then it's O(n) -- see below.

    >> Iterator is part of Collection that does not
    >> guarantee anything, esp. wrt. underlying storage

    ....
    >
    > Iterator has nothing to do with random access, and
    > Iterator is not "part of Collection." There seems to be
    > a communication problem here.


    Riight. Let me try this again in words of one syllable or
    less: Iterator is part of Collections API, it's an iterator
    over "a Collection". Since "a Collection" has no guarantees
    wrt underlying storage (unlike c++ Containers), designers
    of iterator must assume the worst case scenario where cost
    of rewinding the iterator is proportional to number of
    elements in the collection. Creating a new iterator, on
    the other hand, is presumed to be O(1).

    Again, note how Java Iterator is "an iterator", not
    c++-style "ArrayList::Iterator" or "LinkedList::Iterator".

    >> Sure, if it could repoint "this" to the brand-new iterator.
    >> ...

    >
    > No such magic (and it would indeed need to be magical)
    > is needed. My claim is that if List.iterator() has an
    > efficient way to initialize a new Iterator properly, then
    > the same initialization technique is available to the
    > hypothetical Iterator.rewind().


    Que?

    Iterator foo = bar.iterator();
    while( foo.hasNext() ) {
    do stuff
    }
    foo.rewind();
    while( foo.hasNext() ) {
    do more stuff
    }

    Explain to me how this works if foo.rewind() initializes
    a new bar.iterator() "properly".

    > I'm aware that `void' is a method result type, but you
    > expressed a desire for Iterator.next to "return a boolean
    > or void." Not even a `void' method can "return a void."


    "(return a boolean) or void". Get it now?

    Dima
    --
    Relativity, Uncertainty, Incompleteness, Undecidability: choose any four
    Dimitri Maziuk, Dec 21, 2005
    #16
  17. On 2005-12-21, Dimitri Maziuk penned:
    >
    > Riight. Let me try this again in words of one syllable or less:


    Must you be such a jackhole? Do you really think you look clever or
    admirable by putting down other people?

    > Iterator is part of Collections API, it's an iterator over "a
    > Collection". Since "a Collection" has no guarantees wrt underlying
    > storage (unlike c++ Containers), designers of iterator must assume
    > the worst case scenario where cost of rewinding the iterator is
    > proportional to number of elements in the collection. Creating a new
    > iterator, on the other hand, is presumed to be O(1).


    PS you're not very good at counting, are you?

    --
    monique

    Ask smart questions, get good answers:
    http://www.catb.org/~esr/faqs/smart-questions.html
    Monique Y. Mudama, Dec 21, 2005
    #17
  18. Monique Y. Mudama sez:
    > On 2005-12-21, Dimitri Maziuk penned:
    >>
    >> Riight. Let me try this again in words of one syllable or less:

    >
    > Must you be such a jackhole? Do you really think you look clever or
    > admirable by putting down other people?


    public boolean giveafuck() { return false; }

    >> Iterator is part of Collections API, it's an iterator over "a
    >> Collection". Since "a Collection" has no guarantees wrt underlying
    >> storage (unlike c++ Containers), designers of iterator must assume
    >> the worst case scenario where cost of rewinding the iterator is
    >> proportional to number of elements in the collection. Creating a new
    >> iterator, on the other hand, is presumed to be O(1).

    >
    > PS you're not very good at counting, are you?


    Nah, I've computers for that.

    HTH,HAND
    Dima
    --
    Double d = new Double(2.0);
    d = new Double(d.doubleValue() * d.doubleValue());
    I regard Double variables as mutable, considering this one started as 2.0 and
    ended up as 4.0. -- Brendan Guild
    Dimitri Maziuk, Dec 21, 2005
    #18
  19. Hendrik Maryns

    Guest

    Dimitri,

    Here is a list you can use in all of your code that will give you that
    great sequential access you want.

    import java.util.*;

    public class MyList<T> extends ArrayList<T> {

    Random rand = new Random();

    public T get(int index) {
    while (rand.nextInt(index+1) != index) {
    System.out.println("Damn! where did I put that thing again?");
    }
    return super.get(index);
    }

    }
    , Dec 22, 2005
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jakk
    Replies:
    4
    Views:
    12,143
  2. Woodchuck Bill

    Re: GANG CRAP

    Woodchuck Bill, Oct 1, 2005, in forum: HTML
    Replies:
    1
    Views:
    432
    Bob Officer
    Oct 1, 2005
  3. Tim Smith
    Replies:
    2
    Views:
    854
    Tim Smith
    Dec 15, 2004
  4. Replies:
    4
    Views:
    183
    Christophe Grandsire
    Oct 28, 2005
  5. Evertjan.

    Re: Its like the old gang!!!

    Evertjan., Jul 17, 2012, in forum: ASP General
    Replies:
    0
    Views:
    2,012
    Evertjan.
    Jul 17, 2012
Loading...

Share This Page