QUESTION: Can a function be set up as a constant in JS?

Discussion in 'Javascript' started by JJ, Mar 18, 2010.

  1. JJ

    JJ Guest

    Hi all

    I wanted to ask a question about below code I found in a Javascript
    file:

    [---SNIP---]
    // Action Constants
    function Action() {}
    // Action types, Action names
    Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 };
    Action.Name = [ "add.web", "save.web", "close" ];

    ....(continued)...

    function getActionType( iTxnCode, sStatus )
    {
    var iActionType;
    switch( iTxnCode ) {
    case DwngTxn.TpisTxCode.INCIDENT_SUBMITTAL:
    if( !sStatus )
    iActionType = Action.Type.ADD;
    else
    iActionType = Action.Type.UPDATE;
    break;

    ....(continued)...
    [---SNIP---]


    The question is that the person who developed above code seems to be
    creating a function like an object (correct me if I am wrong) and then
    giving it two array(?) attributes "Type" and "Name" which he/she then
    populates with values.

    Later in the code he/she then refers to these in the expressions:
    iActionType = Action.Type.ADD;
    ....and...
    iActionType = Action.Type.UPDATE;



    My question is about that I have tried to find more information on the
    web about doing this but have not seen much of anything. Could anyone
    give me a brief description of what is going on above and what the
    benefits of above is (or is it just to keep the code clean)?

    Thanks in advance,
    JJ, Mar 18, 2010
    #1
    1. Advertising

  2. JJ

    David Mark Guest

    JJ wrote:
    > Hi all
    >
    > I wanted to ask a question about below code I found in a Javascript
    > file:
    >
    > [---SNIP---]
    > // Action Constants
    > function Action() {}
    > // Action types, Action names
    > Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 };
    > Action.Name = [ "add.web", "save.web", "close" ];
    >
    > ...(continued)...


    Appears to be a botched attempt at writing a constructor. I assume they
    call this (once) at some point. They should have just used an object
    literal:-

    var action = {
    type : { ADD: 0, UPDATE: 1, CLOSE: 2 },
    name : [ "add.web", "save.web", "close" ]
    };

    >
    > function getActionType( iTxnCode, sStatus )
    > {
    > var iActionType;
    > switch( iTxnCode ) {
    > case DwngTxn.TpisTxCode.INCIDENT_SUBMITTAL:
    > if( !sStatus )
    > iActionType = Action.Type.ADD;
    > else
    > iActionType = Action.Type.UPDATE;
    > break;
    >
    > ...(continued)...
    > [---SNIP---]
    >
    >
    > The question is that the person who developed above code seems to be
    > creating a function like an object (correct me if I am wrong) and then
    > giving it two array(?) attributes "Type" and "Name" which he/she then
    > populates with values.


    Functions _are_ objects, though using them in lieu of an Object object
    (as is the case here) is not a sound practice.

    >
    > Later in the code he/she then refers to these in the expressions:
    > iActionType = Action.Type.ADD;
    > ...and...
    > iActionType = Action.Type.UPDATE;
    >
    >
    >
    > My question is about that I have tried to find more information on the
    > web about doing this but have not seen much of anything. Could anyone
    > give me a brief description of what is going on above and what the
    > benefits of above is (or is it just to keep the code clean)?


    No benefits (just confusion). It's simply another bad JS example (the
    Web is crawling with them).
    David Mark, Mar 18, 2010
    #2
    1. Advertising

  3. JJ wrote:

    > // Action Constants
    > function Action() {}
    > // Action types, Action names
    > Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 };
    > Action.Name = [ "add.web", "save.web", "close" ];


    Note that those are not real constants, but currently there is no better
    interoperable way.

    > [...]
    > if( !sStatus )
    > iActionType = Action.Type.ADD;
    > else
    > iActionType = Action.Type.UPDATE;


    Can (and IMHO should) be written as follows:

    var iActionType = (sStatus) ? Action.Type.UPDATE : Action.Type.ADD;

    > [...]
    >
    > The question is that the person who developed above code seems to be
    > creating a function like an object (correct me if I am wrong)


    Functions *are* first-class objects in ECMAScript implementations, with a
    double meaning of "object" here.

    > and then giving it two array(?) attributes "Type" and "Name" which he/she
    > then populates with values.


    No, that Function instance is augmented with two _properties_, one storing
    a reference to an Object instance (initialized with `{'...`}') and the
    other storing a reference to an Array instance (initialized with
    `['...`]'). (JavaScript != Java)

    > Later in the code he/she then refers to these in the expressions:
    > iActionType = Action.Type.ADD;
    > ...and...
    > iActionType = Action.Type.UPDATE;
    >
    > My question is about that I have tried to find more information on the
    > web about doing this but have not seen much of anything.


    It really is not much of a mystery if you know that functions are objects.

    > Could anyone give me a brief description of what is going on above and
    > what the benefits of above is (or is it just to keep the code clean)?


    Yes, using an object as if it was a namespace is a way to keep the global
    context clean. The Global Object would then have only one user-defined
    property, not several. However, the function here is a waste of resources
    if it is never called; in that case

    var Action = {
    Type: { ADD: 0, UPDATE: 1, CLOSE: 2 };
    Name: [ "add.web", "save.web", "close" ];
    };

    would have sufficed. In any way the property names of the "non-constants"
    should have started lowercase as they do not denote constructors, i.e.
    `Action.type.ADD' or even `action.type.ADD'.


    PointedEars
    --
    Use any version of Microsoft Frontpage to create your site.
    (This won't prevent people from viewing your source, but no one
    will want to steal it.)
    -- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
    Thomas 'PointedEars' Lahn, Mar 18, 2010
    #3
  4. David Mark wrote:

    > JJ wrote:
    >> The question is that the person who developed above code seems to be
    >> creating a function like an object (correct me if I am wrong) and then
    >> giving it two array(?) attributes "Type" and "Name" which he/she then
    >> populates with values.

    >
    > Functions _are_ objects,


    No doubt about that.

    > though using them in lieu of an Object object
    > (as is the case here) is not a sound practice.


    IBTD. We do not know whether Action() is ever called, and properties on
    constructors and functions in general can be a powerful tool. For example,
    I am using it in my Map implementation as follows:

    /**
    * Returns <code>true</code> if the argument is a {@link Map}
    *
    * @param o : Object
    * @return boolean
    */
    Map.isInstance = function (o) {
    return !!o && o.constructor === this;
    };


    PointedEars
    --
    Anyone who slaps a 'this page is best viewed with Browser X' label on
    a Web page appears to be yearning for the bad old days, before the Web,
    when you had very little chance of reading a document written on another
    computer, another word processor, or another network. -- Tim Berners-Lee
    Thomas 'PointedEars' Lahn, Mar 18, 2010
    #4
  5. JJ

    David Mark Guest

    Thomas 'PointedEars' Lahn wrote:
    > David Mark wrote:
    >
    >> JJ wrote:
    >>> The question is that the person who developed above code seems to be
    >>> creating a function like an object (correct me if I am wrong) and then
    >>> giving it two array(?) attributes "Type" and "Name" which he/she then
    >>> populates with values.

    >> Functions _are_ objects,

    >
    > No doubt about that.
    >
    >> though using them in lieu of an Object object
    >> (as is the case here) is not a sound practice.

    >
    > IBTD. We do not know whether Action() is ever called,


    Ack. I misread partial paste as:-

    function Action() {
    // Action types, Action names
    Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 };
    Action.Name = [ "add.web", "save.web", "close" ];

    ....(continued)...

    Which would seem to imply a botched constructor. I suppose if it were a
    lowercase, then the only complaint is the (seemingly) inexplicable use
    of a Function object where an Object object would be more appropriate.

    > and properties on
    > constructors and functions in general can be a powerful tool.


    Sometimes, but this doesn't look like one of those times.

    > For example,
    > I am using it in my Map implementation as follows:
    >
    > /**
    > * Returns <code>true</code> if the argument is a {@link Map}
    > *
    > * @param o : Object
    > * @return boolean
    > */
    > Map.isInstance = function (o) {
    > return !!o && o.constructor === this;
    > };


    I would lose the truthy test and document that this method accepts
    objects only. If passed undefined (or whatever), it _should_ throw an
    exception, rather than fail silently as, in such a case, there is
    clearly something wrong with the calling code (and the author should
    best be advised of it).

    Consider these two (incorrect) calls of API.isOwnProperty:-

    API.isOwnProperty(undefined, 'someproperty'); // exception
    API.isOwnProperty(someObject, 'somenonexistentproperty'); // true

    ....and granted, the results may _appear_ to be mistakes in the library,
    but the unforgiving nature is fully intended (and definitely more useful
    than glossing over obvious mix-ups in the calling code).

    From the docs:-

    "The isOwnProperty function tests if the specified object does not
    inherit the specified property from its prototype. The property is
    stipulated to exist. This function is typically used to filter inherited
    properties within for-in loops.

    Note the object must be native, not a host object."

    For example, the method is meant to be used in this fashion:-

    for (var i in o) {
    if (API.isOwnProperty(o, i)) {
    // Do something with o
    }
    }

    As an aside, as with some of the array module functions, in some cases
    you can fool this with:

    o.someProperty = undefined;

    The isOwnProperty function will return false unless there is such a
    property defined (meaning it exists and is _not_ the undefined value) on
    o's prototype. I need to add this bit to the documentation. I have an
    idea on how the array module functions can get around this too (without
    using the disallowed - in - operated). You might wonder why I disallow
    the - in - operator in the core. It is because I want to be able to
    test the core (or at least the low-level bits) in _everything_ For
    instance, I just tested the latest build in NN4.7 (minus the Ajax and
    Flash modules as they have try-catch of course) this morning. You might
    also wonder why I would want to test _anything_ in NN4.7. It should be
    obvious that the less features found in a browser, the greater the
    likelihood that gaps in the feature detection will be exposed (and there
    appear to be none at this point).
    David Mark, Mar 18, 2010
    #5
  6. Thomas 'PointedEars' Lahn wrote:

    > /**
    >  * Returns <code>true</code> if the argument is a {@link Map}
    >  *
    >  * @param o : Object
    >  * @return boolean
    >  */
    > Map.isInstance = function (o) {
    >   return !!o && o.constructor === this;
    >
    > };


    But this method is useless in ECMA-262-3 environments. For backward
    compatible can be good, but in inheritance pattern is not very well,
    because doesn't analyse prototype chain.

    function Map2(){}
    Map2.prototype = new Map();
    Map2.prototype.constructor = Map2;

    print(Map.isInstance(new Map2())); //false

    What is a benefit from that method at all? It is try to make
    generalization, which isn't so precisely. I don't see reasons to test
    any objects in this way in implementations, which aren't support
    `instanceof` operator and `Object.prototype.isPrototypeOf (V)` method.
    If i need something like this, I'll do test over interface of object.
    For example if i need to call `getKey' method:

    if (typeof o.getKey == 'function') {
    o.getKey(key);
    }

    If i expect somewhere in my code `Map' instance, I'll write
    documentation about this case. And of course, I'll don't do it test
    above.

    Regards ;~)
    Asen Bozhilov, Mar 18, 2010
    #6
  7. Agreed, also instanceof simply checks the prototype and not the
    constructor

    If we want rely on constructors and their prototype, why create such
    method rather than do this check?

    if (o instanceof Map) {

    }

    it's even shorter than

    if (Map.isInstance(o)) {

    }

    then, as already said

    var MProto = Map.prototype;
    var m = new Map;

    // bye bye
    Map.prototype = {};

    m instanceof Map; // false
    m.constructor === Map; // false

    MProto.isPrototypeOf(m); // true

    accordingly, believing that isInstance won't be changed, I would
    rather go for something like:

    Map.isInstance = (function (__proto__) {
    return function (o) {
    return __proto__.isPrototypeOf(o);
    };
    }(Map.prototype));

    Regards



    On Mar 18, 10:10 pm, Asen Bozhilov <> wrote:
    > Thomas 'PointedEars' Lahn wrote:
    > > /**
    > >  * Returns <code>true</code> if the argument is a {@link Map}
    > >  *
    > >  * @param o : Object
    > >  * @return boolean
    > >  */
    > > Map.isInstance = function (o) {
    > >   return !!o && o.constructor === this;

    >
    > > };

    >
    > But this method is useless in ECMA-262-3 environments. For backward
    > compatible can be good, but in inheritance pattern is not very well,
    > because doesn't analyse prototype chain.
    >
    > function Map2(){}
    > Map2.prototype = new Map();
    > Map2.prototype.constructor = Map2;
    >
    > print(Map.isInstance(new Map2())); //false
    >
    > What is a benefit from that method at all? It is try to make
    > generalization, which isn't so precisely. I don't see reasons to test
    > any objects in this way in implementations, which aren't support
    > `instanceof` operator and `Object.prototype.isPrototypeOf (V)` method.
    > If i need something like this, I'll do test over interface of object.
    > For example if i need to call `getKey' method:
    >
    > if (typeof o.getKey == 'function') {
    >   o.getKey(key);
    >
    > }
    >
    > If i expect somewhere in my code `Map' instance, I'll write
    > documentation about this case. And of course, I'll don't do it test
    > above.
    >
    > Regards ;~)
    Andrea Giammarchi, Mar 19, 2010
    #7
  8. Asen Bozhilov wrote:

    > Thomas 'PointedEars' Lahn wrote:
    >> /**
    >> * Returns <code>true</code> if the argument is a {@link Map}
    >> *
    >> * @param o : Object
    >> * @return boolean
    >> */
    >> Map.isInstance = function (o) {
    >> return !!o && o.constructor === this;
    >>
    >> };

    >
    > But this method is useless in ECMA-262-3 environments. For backward
    > compatible can be good, but in inheritance pattern is not very well,
    > because doesn't analyse prototype chain.


    It does not have to.

    > function Map2(){}
    > Map2.prototype = new Map();


    This inheritance pattern is a problem to begin with. Often discussed,
    often disapproved of.

    > Map2.prototype.constructor = Map2;
    >
    > print(Map.isInstance(new Map2())); //false


    There is no guard against stupidity.

    > What is a benefit from that method at all?


    That a Map instance can be recognized for what it is. This is important
    because there are some methods that are only available to Map instances.
    RTSL.

    > if (typeof o.getKey == 'function') {
    > o.getKey(key);
    > }


    Doesn't apply here.


    PointedEars
    --
    realism: HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness: XHTML 1.1 as application/xhtml+xml
    -- Bjoern Hoehrmann
    Thomas 'PointedEars' Lahn, Mar 19, 2010
    #8
  9. Andrea Giammarchi wrote:

    > Agreed, also instanceof simply checks the prototype and not the
    > constructor


    The intention here was to avoid just that.

    > If we want rely on constructors and their prototype, why create such
    > method rather than do this check?
    >
    > if (o instanceof Map) {
    >
    > }
    >
    > it's even shorter than
    >
    > if (Map.isInstance(o)) {
    >
    > }


    And it is less compatible.

    > [non sequitur]
    >
    > [top post]


    Learn to quote.


    PointedEars
    --
    Anyone who slaps a 'this page is best viewed with Browser X' label on
    a Web page appears to be yearning for the bad old days, before the Web,
    when you had very little chance of reading a document written on another
    computer, another word processor, or another network. -- Tim Berners-Lee
    Thomas 'PointedEars' Lahn, Mar 19, 2010
    #9
  10. On Mar 19, 1:28 pm, Thomas 'PointedEars' Lahn <>
    wrote:
    > And it is less compatible.


    tell me which browser exactly gives you problem with instanceof ...
    and if you ends up with IE4 I do believe you have no features
    detections for those cases where try catch are essential ... so I hope
    you don't consider your library more robust and I have already wrote
    an alternative based on the true inheritance ...
    Andrea Giammarchi, Mar 19, 2010
    #10
  11. Andrea Giammarchi wrote:

    [Context restored]
    > Thomas 'PointedEars' Lahn wrote:
    >> > If we want rely on constructors and their prototype, why create such
    >> > method rather than do this check?
    >> >
    >> > if (o instanceof Map) {
    >> >
    >> > }
    >> >
    >> > it's even shorter than
    >> >
    >> > if (Map.isInstance(o)) {
    >> >
    >> > }

    >> And it is less compatible.

    >
    > tell me which browser exactly gives you problem with instanceof ...


    Those using implementations based on ECMAScript < 3, JavaScript < 1.5,
    or JScript < 5.0. Yes, that includes IE 4.x.

    > and if you ends up with IE4 I do believe you have no features
    > detections for those cases where try catch are essential ...


    try..catch can be wrapped so that a less capable compiler does not find it
    (so no SyntaxError there).

    > so I hope you don't consider your library more robust


    Yes, I do.

    > and I have already wrote an alternative based on the true inheritance ...


    Inheritance is beside the point here, and your alternative suggestion is
    not even compatible to non-Geckos. Talk about robust libraries.

    BTW, trimming quotes means to leave the relevant parts.


    PointedEars
    --
    var bugRiddenCrashPronePieceOfJunk = (
    navigator.userAgent.indexOf('MSIE 5') != -1
    && navigator.userAgent.indexOf('Mac') != -1
    ) // Plone, register_function.js:16
    Thomas 'PointedEars' Lahn, Mar 19, 2010
    #11
  12. Thomas 'PointedEars' Lahn wrote:

    > That a Map instance can be recognized for what it is.  This is important
    > because there are some methods that are only available to Map instances.  
    > RTSL.


    It's a flawed argument. If you need to do it something, only with Map
    instances. These methods should be with `private` signatures. There
    no need dummy method like that for observing `private` properties.

    "RTSL" - Don't use repeatedly abbreviations. They are with different
    meaning, depend by context. And i don't need to know each abbreviation
    to understand your post. In that context, "RTSL" mean "Read The
    Source, Luke".
    First of all, my name isn't Luke. So that abbreviation is nonsense at
    all. Second, there aren't any links to your source code. Third, i was
    read your code using google.

    If you want better meaning of RTSL:

    Rewrite The Source, Lahn.
    Asen Bozhilov, Mar 19, 2010
    #12
  13. Thomas 'PointedEars' Lahn wrote:
    > Andrea Giammarchi wrote:


    > > and I have already wrote an alternative based on the true inheritance ....

    >
    > Inheritance is beside the point here, and your alternative suggestion is
    > not even compatible to non-Geckos.  Talk about robust libraries.


    Are you read his code? It's compatible with any ECMA-262
    implementations, because `__proto__` is valid Identifier. Of course
    Identifiers name like that aren't good practice. But before you blame
    someone, please read precisely him code. Thanks.
    Asen Bozhilov, Mar 19, 2010
    #13
  14. Asen Bozhilov wrote:

    > Thomas 'PointedEars' Lahn wrote:
    >> Andrea Giammarchi wrote:
    >> > and I have already wrote an alternative based on the true inheritance
    >> > ...

    >>
    >> Inheritance is beside the point here, and your alternative suggestion is
    >> not even compatible to non-Geckos. Talk about robust libraries.

    >
    > Are you read his code? It's compatible with any ECMA-262
    > implementations, because `__proto__` is valid Identifier. Of course
    > Identifiers name like that aren't good practice. But before you blame
    > someone, please read precisely him code. Thanks.


    (You are still writing a lot of gibberish.)

    Yes, he got me confused (intentionally?) with the __proto__ argument.
    However, it is safe to say that while his code is compatible to some non-
    Geckos, it is not as compatible as mine, and it certainly is not equivalent
    to mine (which was the point of the exercise).

    FYI, in the process I have updated the (hopefully-soon-to-be) next release
    of the ECMAScript Support Matrix¹ as follows:

    ECMAScript JavaScript JScript V8 JSC Opera KJS
    [1] 5 [15.2.4.6] 1.5 5.5.6330 2.0 525.13 5.02 4.3.4
    ___
    [1] Object.prototype.isPrototypeOf(Object) : boolean


    PointedEars
    ___________
    ¹ <http://PointedEars.de/es-matrix>
    --
    Prototype.js was written by people who don't know javascript for people
    who don't know javascript. People who don't know javascript are not
    the best source of advice on designing systems that use javascript.
    -- Richard Cornford, cljs, <f806at$ail$1$>
    Thomas 'PointedEars' Lahn, Mar 19, 2010
    #14
  15. Thomas 'PointedEars' Lahn wrote:

    > ECMAScript JavaScript JScript V8 JSC Opera KJS
    > [1] 5 [15.2.4.6] 1.5 5.5.6330 2.0 525.13 5.02 4.3.4
    > ___
    > [1] Object.prototype.isPrototypeOf(Object) : boolean


    Should be ES 3, not 5. Further corrections are welcome (as always).


    PointedEars
    --
    Use any version of Microsoft Frontpage to create your site.
    (This won't prevent people from viewing your source, but no one
    will want to steal it.)
    -- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
    Thomas 'PointedEars' Lahn, Mar 19, 2010
    #15
  16. Thomas 'PointedEars' Lahn wrote:

    > (You are still writing a lot of gibberish.)


    You can interpret however you want.

    > Yes, he got me confused (intentionally?) with the __proto__ argument.


    No, there isn't world conspiracy against you.

    > ¹  <http://PointedEars.de/es-matrix>


    Why do you group in table unicode escape sequences for string literals
    and regular expression literals? While escape sequences in string
    literals are documented in ECMA-262-1, escape sequences in regular
    expression literals are part of ECMA-262 standard edition 3.
    And in table there isn't unicode escape sequences as part of
    IdentifierName, which ECMA-262-3 allow.
    Asen Bozhilov, Mar 20, 2010
    #16
  17. > Yes, he got me confused (intentionally?) with the __proto__ argument.

    __proto__ property points the inherited prototype

    Since what you want to do is to know if an object inherited from
    Map.prototype, where in Gecko Map.prototype === new Map().__proto__, I
    have used that syntax to explain the concept behind the check.

    Moreover, the === operator does not tell us if the instance inherits
    from extended prototype, this is why isPrototypeOf is required.

    function Map() {}
    function Map2() {}
    Map2.prototype = new Map;

    var m = new Map;
    var m2 = new Map2;

    m2.__proto__ === Map.prototype; // false

    m.__proto__.isPrototypeOf(m2); // true

    // ... and ...
    m.__proto__ === Map.prototype; // true

    So, how can you get confuse about that variable called __proto__?

    Finally, which part of an exposed public constructor property unable
    to tell you about inheritance, if any, can be considered more robust?
    And why are don't you deal with IE3 as well and possibly with a
    browser for Commodore 64?

    Regards
    Andrea Giammarchi, Mar 20, 2010
    #17
  18. by the way, I have just remembered when I was playing with some T-Rex
    and IE4 I wrote this library which is compatible and normalizes death
    browsers:
    http://devpro.it/JSL/

    If interested, there are few interesting things there, have a look if
    interested.

    Regards
    Andrea Giammarchi, Mar 20, 2010
    #18
  19. wtf ... I knew I had to drink more coffee, sorry for 80% of typos
    Andrea Giammarchi, Mar 20, 2010
    #19
  20. On Mar 20, 4:19 am, Andrea Giammarchi <>
    wrote:
    > by the way, I have just remembered when I was playing with some T-Rex
    > and IE4 I wrote this library which is compatible and normalizes death
    > browsers:http://devpro.it/JSL/
    >
    > If interested, there are few interesting things there, have a look if
    > interested.
    >
    > Regards


    From http://devpro.it/JSL/JSLOpenSource.js
    ---------
    if(typeof(XMLHttpRequest)==="undefined"){XMLHttpRequest=function(){
    var tmp=null,elm=navigator.userAgent;
    if(elm.toUpperCase().indexOf("MSIE 4")<0&&window.ActiveXObject)
    tmp=elm.indexOf("MSIE 5")<0?new ActiveXObject("Msxml2.XMLHTTP"):new
    ActiveXObject("Microsoft.XMLHTTP");
    return tmp;
    }};
    ----------

    Whats with the sniffing?
    Michael Haufe (\TNO\), Mar 20, 2010
    #20
    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. Christopher M. Lusardi
    Replies:
    1
    Views:
    4,072
  2. Martin Magnusson
    Replies:
    2
    Views:
    492
    John Harrison
    Oct 8, 2004
  3. Tor Erik Soenvisen
    Replies:
    14
    Views:
    544
    Tim Roberts
    Nov 23, 2006
  4. Replies:
    4
    Views:
    331
    Keith Thompson
    Dec 14, 2006
  5. Fredxx
    Replies:
    3
    Views:
    634
    Martin Thompson
    Jul 15, 2009
Loading...

Share This Page