Which way will take more memory?

Discussion in 'ASP General' started by Rabbit63, Sep 19, 2003.

  1. Rabbit63

    Rabbit63 Guest

    Hi:

    I want to show a set of records in the database table on the clicnt browser.
    I have two ways to do this (writen in JScript):

    1.The first way is:

    <%
    var sql = "select firstname from table1";
    var obj=new ActiveXObject("ADODB.Recordset");
    obj.open(sql, conn);
    while(!obj.EOF)
    {
    Response.write(obj("firstname") + "<br>");
    obj.movenext();
    }
    obj.close();
    %>


    2. The second way is:
    <%
    var arr=new Array();
    var sql = "select firstname from table1";
    var obj=new ActiveXObject("ADODB.Recordset");
    obj.open(sql, conn);
    while(!obj.EOF)
    {
    arr[arr.length] = new String(obj("firstname"));
    obj.movenext();
    }
    obj.close();

    .......


    for(i=0;i<arr.length;i++)
    {
    document.write(arr + "<br>");
    }
    %>


    I think the second way is more flexible but it will take nuch more memory
    than the first way, because the array "arr" will take more memory. Am I
    correct? Do you think the second way will need more server resources? Do you
    have better idea to improve the second way?

    The reason that I tried the second way is that I wanted to make my server
    side programs (most writen in JScript) be object-based (not OOP) programming
    style. But I am doubt that the object-based programs will take much more
    memory or server resources.

    Thank you very much!

    Qing
     
    Rabbit63, Sep 19, 2003
    #1
    1. Advertising

  2. I don't know about resources - though if you set the recordset to NOTHING as
    soon as you're done with it that should free those resources up - but the
    second method will be noticeably faster.

    - Wm "Arrays made me a better person" Morris


    --
    William Morris
    Product Development, Seritas LLC


    "Rabbit63" <> wrote in message
    news:...
    > Hi:
    >
    > I want to show a set of records in the database table on the clicnt

    browser.
    > I have two ways to do this (writen in JScript):
    >
    > 1.The first way is:
    >
    > <%
    > var sql = "select firstname from table1";
    > var obj=new ActiveXObject("ADODB.Recordset");
    > obj.open(sql, conn);
    > while(!obj.EOF)
    > {
    > Response.write(obj("firstname") + "<br>");
    > obj.movenext();
    > }
    > obj.close();
    > %>
    >
    >
    > 2. The second way is:
    > <%
    > var arr=new Array();
    > var sql = "select firstname from table1";
    > var obj=new ActiveXObject("ADODB.Recordset");
    > obj.open(sql, conn);
    > while(!obj.EOF)
    > {
    > arr[arr.length] = new String(obj("firstname"));
    > obj.movenext();
    > }
    > obj.close();
    >
    > ......
    >
    >
    > for(i=0;i<arr.length;i++)
    > {
    > document.write(arr + "<br>");
    > }
    > %>
    >
    >
    > I think the second way is more flexible but it will take nuch more memory
    > than the first way, because the array "arr" will take more memory. Am I
    > correct? Do you think the second way will need more server resources? Do

    you
    > have better idea to improve the second way?
    >
    > The reason that I tried the second way is that I wanted to make my server
    > side programs (most writen in JScript) be object-based (not OOP)

    programming
    > style. But I am doubt that the object-based programs will take much more
    > memory or server resources.
    >
    > Thank you very much!
    >
    > Qing
    >
    >
    >
    >
    >
     
    WIlliam Morris, Sep 19, 2003
    #2
    1. Advertising

  3. Rabbit63

    dlbjr Guest

    This will out perform both methods.

    var sql = "select firstname from table1";
    var obj = new ActiveXObject("ADODB.Recordset");
    obj.open(sql,conn,adOpenForwardOnly,adLockReadOnly);
    var arr = obj.GetRows;
    obj.close();

    -dlbjr

    Discerning resolutions for the alms
     
    dlbjr, Sep 19, 2003
    #3
  4. "WIlliam Morris" wrote:
    >
    > I don't know about resources - though if you set the recordset
    > to NOTHING as soon as you're done with it that should free
    > those resources up - but the second method will be noticeably
    > faster.


    Re-read his post. He's using JScript on the server, so there is no need to
    set the recordset to NOTHING (nor a means to do so).

    And I'm unconvinced the second will be faster. That may have been true with
    VBScript/IIS4, but this is a completely different situation. As has been
    noted in other threads, VBScript and JScript have different strengths and
    weaknesses, and each does some tasks faster than the other.


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 20, 2003
    #4
  5. "Rabbit63" wrote:
    >
    > I want to show a set of records in the database table on the clicnt

    browser.
    > I have two ways to do this (writen in JScript):
    >
    > 1.The first way is:
    >
    > <%
    > var sql = "select firstname from table1";
    > var obj=new ActiveXObject("ADODB.Recordset");
    > obj.open(sql, conn);
    > while(!obj.EOF)
    > {
    > Response.write(obj("firstname") + "<br>");
    > obj.movenext();
    > }
    > obj.close();
    > %>
    >
    >
    > 2. The second way is:
    > <%
    > var arr=new Array();
    > var sql = "select firstname from table1";
    > var obj=new ActiveXObject("ADODB.Recordset");
    > obj.open(sql, conn);
    > while(!obj.EOF)
    > {
    > arr[arr.length] = new String(obj("firstname"));
    > obj.movenext();
    > }
    > obj.close();
    >
    > ......
    >
    >
    > for(i=0;i<arr.length;i++)
    > {
    > document.write(arr + "<br>");
    > }
    > %>
    >
    >
    > I think the second way is more flexible but it will take nuch more memory
    > than the first way, because the array "arr" will take more memory. Am I
    > correct? Do you think the second way will need more server resources? Do

    you
    > have better idea to improve the second way?
    >
    > The reason that I tried the second way is that I wanted to make my server
    > side programs (most writen in JScript) be object-based (not OOP)

    programming
    > style. But I am doubt that the object-based programs will take much more
    > memory or server resources.


    We have a pretty large number of JScript/ASP apps that use the following
    methodology, and have never had performance issues, despite fairly heavy
    usage. Here's the basic template, in which I implement your task:

    <% var Page = new PageVariables() %>
    <HTML> ... <%=Page.NameList%> ... </HTML>
    <%
    function PageVariables() {
    var CN = Server.CreateObject("ADODB.Connection"),
    NameList = []
    CN.Open( {connection string} )
    var RS = CN.Execute( {sql string} )
    while(!RS.EOF) {
    NameList.push(RS.Fields("firstname").Item)
    RS.MoveNext()
    }
    this.NameList = NameList.join("<BR>\r\n")
    try { RS.Close() } catch(e) {}
    try { CN.Close() } catch(e) {}
    }
    %>

    This approach has several benefits. The first is that you don't put anything
    into the Response Buffer until all of your server-side processing is
    completed. This maximizes your flexibility, since, for example, you may
    choose to Response.Redirect if certain conditions are met.

    Another benefit is that your HTML is abstracted from your server-side
    scripting (meaning it's no longer interlaced), so you can hand the HTML
    template portion to your graphic designer and let him put layout around your
    content tokens (<%=Page.varname%>) in whatever order he likes. Even if you
    do the whole thing yourself, the separation if HTML and processing into two
    sections vastly improves readability.

    Next benefit: A clean namespace. If you need to do a little interlacing, you
    don't have to worry about duplication of variable names, since everything is
    a property of the Page object, and all of its transient variables have
    vanished. This will never present a namespace conflict:

    <% for (var i=0; i<Page.OptionList.length; i++) { %>
    <OPTION VALUE="<%=Page.OptionList.Value%>">
    <%=Page.OptionList.Text%></OPTION>
    <% } %>

    There was another suggestion that you use RS.GetRows(), but I'm betting it
    wouldn't help you. For one thing, it returns a 2D array, which JScript does
    not understand, and which actually gets flattened into a single array with
    twice the length and none of the structure. More importantly, it's virtually
    useless if you are asking for more than one field, which is usually the
    case. I assume your example is a simplification of your task, just as my
    example is a great simplification** of my solution.

    At this point, I'd like to address your specific question regarding
    resources. Does this technique require more memory at run-time? Yes, but
    trivially. The transient variables (local to the function) have extremely
    short lifespans, and by the time you hit the HTML layout, the only thing in
    memory is the actual content you will be displaying.


    =====
    **I almost never interlace, for example. If I want to build a set of OPTIONs
    for a SELECT element, I construct a string containing all of the options in
    all of their detail. This, in turn, I generate from a single array by
    calling a custom Array method defined in a site-wide include of prototype
    extensions. The second example above simplifies to the following (1)
    processing and (2) presentation lines:

    1. this.OptionList = OptionArray.toOptions(defaultVal)
    2. <SELECT><%=Page.OptionList%></SELECT>

    Another simplification -- I *rarely* use SQL strings, except to call stored
    procedures. And I always use ADODB.Command for inserts, which is a topic for
    another thread. Furthermore, it is rare for me to request a single field
    from the DB, as I suspect is the case for most people. I can think of a
    bunch more, but I'm getting tired and hungry, so I'm going to end it here
    leave the rest as an exercise.


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 20, 2003
    #5
  6. "Dave Anderson" <> wrote in message
    news:...
    > "WIlliam Morris" wrote:
    > >
    > > I don't know about resources - though if you set the recordset
    > > to NOTHING as soon as you're done with it that should free
    > > those resources up - but the second method will be noticeably
    > > faster.

    >
    > Re-read his post. He's using JScript on the server, so there is no

    need to
    > set the recordset to NOTHING (nor a means to do so).


    There is both a need and a means for setting a recordset to Nothing.
    Here is an article:
    http://groups.google.com/groups?threadm=#T9kWfgoAHA.1840@tkmsftngp03

    That being said, I imagine GetString would have been the fastest and
    least resource intensive option in this case.

    -Chris
     
    Chris Hohmann, Sep 20, 2003
    #6
  7. Rabbit63

    Bob Barrows Guest

    Dave Anderson wrote:
    >
    > There was another suggestion that you use RS.GetRows(), but I'm
    > betting it wouldn't help you. For one thing, it returns a 2D array,
    > which JScript does not understand, and which actually gets flattened
    > into a single array with twice the length and none of the structure.
    > More importantly, it's virtually useless if you are asking for more
    > than one field, which is usually the case.
    >

    Actually, GetRows returns a VBArray
    (http://msdn.microsoft.com/library/en-us/script56/html/js56jsobjVBArray.asp)
    which jscript handles quite nicely
    (http://www.aspalliance.com/PeterJohnson/JSGetRows.asp) .

    I've never tested the performance of this, but I suspect that even though it
    is heavier than a vbs array, it will still outperform a heavy cursor.

    I will agree that there is probably less benefit in jscript than there is in
    vbs.

    Bob Barrows
     
    Bob Barrows, Sep 20, 2003
    #7
  8. "Chris Hohmann" wrote:
    >>
    >> Re-read his post. He's using JScript on the server, so there
    >> is no need to set the recordset to NOTHING (nor a means to do
    >> so).

    >
    > There is both a need and a means for setting a recordset to
    > Nothing.


    Assuming that there is...

    > http://groups.google.com/groups?threadm=#T9kWfgoAHA.1840@tkmsftngp03


    ....this thread does not make the "need" argument. I'll grant that you may be
    able to construct a need to set the .ActiveConnection property to Nothing,
    but this discussion does not address setting the Recordset to Nothing.

    > That being said, I imagine GetString would have been the fastest
    > and least resource intensive option in this case.


    Assuming a single field is requested, probably. But that is probably not the
    case (I know his example only asks for one field, but it's an EXAMPLE, and
    probably not fully representative of his real goal).


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 22, 2003
    #8
  9. "Dave Anderson" <> wrote in message
    news:...
    > "Chris Hohmann" wrote:
    > >>
    > >> Re-read his post. He's using JScript on the server, so there
    > >> is no need to set the recordset to NOTHING (nor a means to do
    > >> so).

    > >
    > > There is both a need and a means for setting a recordset to
    > > Nothing.

    >
    > Assuming that there is...


    Assuming there is what, a need or a means? I think we can both agree
    that there is indeed a means to setting a recordset object to Nothing in
    JScript. In fact there are several of them. As for the need, see below.

    > >

    http://groups.google.com/groups?threadm=#T9kWfgoAHA.1840@tkmsftngp03
    >
    > ...this thread does not make the "need" argument. I'll grant that you

    may be
    > able to construct a need to set the .ActiveConnection property to

    Nothing,
    > but this discussion does not address setting the Recordset to Nothing.


    You are correct, the aforementioned thread does not make a specific
    argument for the need to set recordset objects to Nothing. That
    agrument/assumption is mine, just as the argument/assumption that there
    is no need to set recordset objects to Nothing in JScript is yours. My
    rationale for the need to explicitly set recordsets to Nothing is this.
    By explicitly setting a recordset object to Nothing, the resources used
    by that object are released and as such can be used in the processing of
    the remainder of the page. As such, this can improve the performance of
    a page and reduce its overall resource requirements which was the
    question posed by the OP.

    While the above thread does not argue for the need to set recordsets to
    Nothing, it does address the issue, although that is not readily
    apparent on first read. Here's a snippet from message three (3) in the
    thread:

    --- begin ---
    3) My solution: simply get a reference to the default value for an
    unopened
    recordset, which just happens to be Nothing (VT_DISPATCH):

    //---- Custom 'Nothing' equivalent for disconnected recordsets ----
    var oRS = Server.CreateObject('ADODB.Recordset');
    var Nothing = oRS.ActiveConnection;
    var oRS = Nothing;
    --- end ---

    Take note of the last line in which the recordset object is set to
    Nothing.


    > > That being said, I imagine GetString would have been the fastest
    > > and least resource intensive option in this case.

    >
    > Assuming a single field is requested, probably. But that is probably

    not the
    > case (I know his example only asks for one field, but it's an EXAMPLE,

    and
    > probably not fully representative of his real goal).


    Even with multiple fields, GetString is the fastest method. GetString's
    limitation is not the number of fields in the recordset, it is the
    inability/difficulty in performing row, column or cell based processing.
    Here's an article that analyses the pros and cons of various methods of
    rendering data from a recordset.

    http://aspfaq.com/2467

    I would be genuinely interested in hearing about any method that could
    out perform GetString.

    -Chris
     
    Chris Hohmann, Sep 22, 2003
    #9
  10. "Chris Hohmann" wrote:
    >
    > While the above thread does not argue for the need to set
    > recordsets to Nothing, it does address the issue, although
    > that is not readily apparent on first read. Here's a snippet
    > from message three (3) in the thread:
    >
    > var oRS = Server.CreateObject('ADODB.Recordset');
    > var Nothing = oRS.ActiveConnection;
    > var oRS = Nothing;


    This is superficial at best. The original post asked about setting the
    ..ActiveConnection property (detailing a specific error), and this response,
    while describing a means to assign the value Nothing, redeclares* the
    variable and assigns it the constant value Nothing. Why is it different from
    this?

    var oRS = Server.CreateObject('ADODB.Recordset')
    oRS = Math.PI

    From a practical standpoint, it isn't. You assign a constant value to a
    variable -- not exactly earth-shattering stuff, and NOT AT ALL equivalent to
    the VBScript:

    Set oRS = Nothing

    The VBScript keyword Nothing has a specific purpose -- to free resources. It
    is absent from JScript for a reason. I have yet to see an argument more
    sophisticated than "that's the way it's done in VBScript" for freeing memory
    in garbage-collected JScript**. Perhaps you could provide one.

    > ...Even with multiple fields, GetString is the fastest method.
    > GetString's limitation is not the number of fields in the
    > recordset, it is the inability/difficulty in performing row,
    > column or cell based processing...


    That was more or less my point. I am aware that GetString() uses row AND
    column delimiters, but simple tabular display is frequently insufficient,
    and thus is GetString(). I beg forgiveness for my lack of clarity on this
    point.


    *Or worse -- erroneously assumes the var statement is equivalent to
    VBScript's Set statement.

    **Though you may have noted from my other post that I *do* close recordsets
    and connections. At some point in the past, I read that when one of them is
    destroyed, the close() method is implicitly called. Not sure how that
    translates in the JScript world, I have always just closed them. But my
    other point remains -- we NEVER set JScript variables to Nothing, and have
    never suffered a resulting or performance/resource drain, as we did before
    conversion from VBScript.


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 22, 2003
    #10
  11. "Dave Anderson" <> wrote in message
    news:eTT%...
    > "Chris Hohmann" wrote:
    > >
    > > While the above thread does not argue for the need to set
    > > recordsets to Nothing, it does address the issue, although
    > > that is not readily apparent on first read. Here's a snippet
    > > from message three (3) in the thread:
    > >
    > > var oRS = Server.CreateObject('ADODB.Recordset');
    > > var Nothing = oRS.ActiveConnection;
    > > var oRS = Nothing;

    >
    > This is superficial at best. The original post asked about setting the
    > .ActiveConnection property (detailing a specific error), and this

    response,
    > while describing a means to assign the value Nothing, redeclares* the
    > variable and assigns it the constant value Nothing. Why is it

    different from
    > this?
    >
    > var oRS = Server.CreateObject('ADODB.Recordset')
    > oRS = Math.PI
    >
    > From a practical standpoint, it isn't. You assign a constant value to

    a
    > variable -- not exactly earth-shattering stuff, and NOT AT ALL

    equivalent to
    > the VBScript:
    >
    > Set oRS = Nothing
    >
    > The VBScript keyword Nothing has a specific purpose -- to free

    resources. It
    > is absent from JScript for a reason. I have yet to see an argument

    more
    > sophisticated than "that's the way it's done in VBScript" for freeing

    memory
    > in garbage-collected JScript**. Perhaps you could provide one.


    I can think of three(3) off the top of my head:
    1. Disconnected recordsets (you already knew that)
    2. Releasing COM objects. Google search on JScript, COM and Nothing.
    3. Anytime the variant subtype VT_DISPATCH is expected.


    > > ...Even with multiple fields, GetString is the fastest method.
    > > GetString's limitation is not the number of fields in the
    > > recordset, it is the inability/difficulty in performing row,
    > > column or cell based processing...

    >
    > That was more or less my point. I am aware that GetString() uses row

    AND
    > column delimiters, but simple tabular display is frequently

    insufficient,
    > and thus is GetString(). I beg forgiveness for my lack of clarity on

    this
    > point.


    No need to beg. I will point out that in my original reply, I was
    careful to say "in this case". Discussions of frequency and
    probabilities is not relavent to this particular thread. Nor is guessing
    at what is "fully representative" of the OP's real goal. Based upon the
    information available to us, I would like to reaffirm my original
    position. IN THIS CASE, GetString would have been the fastest and least
    resource intensive option.


    > *Or worse -- erroneously assumes the var statement is equivalent to
    > VBScript's Set statement.


    I cannot speak intelligently on what assumptions the author may or may
    not have made. Superficial, erroneous (with respect to the
    interpretation of the var statement) or otherwise, it does show an
    example of setting a recordset object to Nothing.


    > **Though you may have noted from my other post that I *do* close

    recordsets
    > and connections. At some point in the past, I read that when one of

    them is
    > destroyed, the close() method is implicitly called. Not sure how that
    > translates in the JScript world, I have always just closed them. But

    my
    > other point remains -- we NEVER set JScript variables to Nothing, and

    have
    > never suffered a resulting or performance/resource drain, as we did

    before
    > conversion from VBScript.


    As a proof of concept, try instantiating Excel from JScript. Or even
    Access for that matter. Obviously, do not do this on a production
    server, as you may need to halt the JScript engine to for garbage
    collection (i.e. restart IIS) or reboot your machine.

    -Chris

    P.S. There is in fact an undocumented GarbageCollect() function in
    JScript that forces immediate garbage collection. However developers are
    strongly urged (by Microsoft) not to use it in production code.
     
    Chris Hohmann, Sep 22, 2003
    #11
  12. "Chris Hohmann" wrote:
    >>
    >> I have yet to see an argument more sophisticated than "that's
    >> the way it's done in VBScript" for freeing memory in garbage-
    >> collected JScript...

    >
    > I can think of three(3) off the top of my head:
    > 1. Disconnected recordsets (you already knew that)


    I always thought the benefit of disconnected recordsets was freeing
    CONNECTIONS, not MEMORY. It would otherwise hardly matter if you just waited
    until the end of your script to set everything to Nothing, as the memory
    taken by the Connection object would be freed up there just as completely as
    when you create the Recordset.

    Can you make a case that disconnected recordsets free more memory?


    > 2. Releasing COM objects. Google search on JScript, COM and Nothing.


    Yeah - the word "Nothing" doesn't make this search impossible to weed
    through. I found no discussions of the benefit, but did find plenty of
    advice to assign null values, and one obscure reference to the undocumented
    "delete" keyword in this KB article:
    http://support.microsoft.com:80/support/kb/articles/Q229/6/93.asp


    > 3. Anytime the variant subtype VT_DISPATCH is expected.


    That may be a reason, but it's not accompanied by an argument. I stand by my
    statement.


    > As a proof of concept, try instantiating Excel from JScript.
    > Or even Access for that matter.


    Why would I invoke a desktop interface with a service? You'll have to be a
    bit more specific for this to make any sense.


    > P.S. There is in fact an undocumented GarbageCollect() function
    > in JScript that forces immediate garbage collection. However
    > developers are strongly urged (by Microsoft) not to use it in
    > production code.


    I already knew about that one, but not delete. I assume the same warning
    applies to delete as GarbageCollect().



    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 23, 2003
    #12
  13. "Dave Anderson" <> wrote in message
    news:3f6f90c3$0$163$...
    > "Chris Hohmann" wrote:
    > >>
    > >> I have yet to see an argument more sophisticated than "that's
    > >> the way it's done in VBScript" for freeing memory in garbage-
    > >> collected JScript...

    > >
    > > I can think of three(3) off the top of my head:
    > > 1. Disconnected recordsets (you already knew that)

    >
    > I always thought the benefit of disconnected recordsets was freeing
    > CONNECTIONS, not MEMORY. It would otherwise hardly matter if you just

    waited
    > until the end of your script to set everything to Nothing, as the

    memory
    > taken by the Connection object would be freed up there just as

    completely as
    > when you create the Recordset.
    >
    > Can you make a case that disconnected recordsets free more memory?


    The wording was somewhat confusing. I thought 'arguments more
    sophisticated than "that's the way it's done in VBScript"... ' meant you
    wanted examples besides just releasing memory. Now that I understand, I
    refer you to item 2, which is all about releasing memory.

    > > 2. Releasing COM objects. Google search on JScript, COM and Nothing.

    >
    > Yeah - the word "Nothing" doesn't make this search impossible to weed
    > through. I found no discussions of the benefit, but did find plenty of
    > advice to assign null values, and one obscure reference to the

    undocumented
    > "delete" keyword in this KB article:
    > http://support.microsoft.com:80/support/kb/articles/Q229/6/93.asp


    I should have been clear. I meant do a Google GROUPS search. Here's the
    first thread that comes up:
    http://groups.google.com/groups?threadm=#Lbpzjeu$GA.129@cppssbbsa03


    > > 3. Anytime the variant subtype VT_DISPATCH is expected.

    >
    > That may be a reason, but it's not accompanied by an argument. I stand

    by my
    > statement.


    Item 3 is simple a generalization for items 1 and 2 which represent
    specific instances where Nothing (VT_DISPATCH) is needed in JScript. So
    here's the accompanying argument: If I don't have access to Nothing
    (VT_DISPATCH) then I cannot interact with objects that expect to be
    passed the Nothing value. Object that fall in this category include
    ADO.Recordsets and COM objects which do not implement a custom method to
    call the Release() function and instead rely upon the behavior of
    Nothing under VBScript to release resources.


    > > As a proof of concept, try instantiating Excel from JScript.
    > > Or even Access for that matter.

    >
    > Why would I invoke a desktop interface with a service? You'll have to

    be a
    > bit more specific for this to make any sense.


    I was not suggesting that you make a habit of instantiating Excel from
    ASP. You said you never experienced a performance/resource drain by not
    setting variables to Nothing in JScript. I was simply providing you with
    a real life example of how such a resource/drain could occur. As for why
    you want to instantiante Excel from ASP, some developer use Excel as a
    dynamic graphing engine. Please note, I am not one of them. For dynamic
    graphing I use Office Web Components (OWC).


    > > P.S. There is in fact an undocumented GarbageCollect() function
    > > in JScript that forces immediate garbage collection. However
    > > developers are strongly urged (by Microsoft) not to use it in
    > > production code.

    >
    > I already knew about that one, but not delete. I assume the same

    warning
    > applies to delete as GarbageCollect().


    No, delete is a documented and supported part of JScript:
    http://msdn.microsoft.com/library/en-us/script56/html/js56jsoprdelete.asp
    However, delete has no effect on garbage collection, so it is not
    relevant to this discussion.

    -Chris
     
    Chris Hohmann, Sep 23, 2003
    #13
  14. "Chris Hohmann" wrote:
    >
    > I should have been clear. I meant do a Google GROUPS search. Here's the
    > first thread that comes up:
    > http://groups.google.com/groups?threadm=#Lbpzjeu$GA.129@cppssbbsa03


    OK - I'll grant that some COM objects may occasionally need a property set
    to Nothing or have Nothing passed as a parameter to a method. That is a
    limitation of particular objects that cannot be avoided. But that isn't at
    all the same as assigning Nothing to a variable to "free resources".

    Recall my original objection was to this:

    "...if you set the recordset to NOTHING as soon as you're
    done with it that should free those resources up..."

    And while my assertion regarding the lack of MEANS was incorrect, I remain
    unconvinced that the rest of my response was in error.

    Re-reading this thread, I can see where you might think I'm just being
    argumentative. But I really have a concern here, since we have so many
    scripts written in JScript that do not use many of the practices suggested
    here (assigning null or Nothing, using disconnected recordsets, etc.). If I
    am splitting hairs, I am doing so to get as much clarity as possible. I want
    my solutions to be robust, and so far they appear to be, but some of the
    claims made here challenge that notion.


    > ...If I don't have access to Nothing (VT_DISPATCH) then I cannot
    > interact with objects that expect to be passed the Nothing value.
    > Object that fall in this category include ADO.Recordsets and COM
    > objects which do not implement a custom method to call the
    > Release() function and instead rely upon the behavior of Nothing
    > under VBScript to release resources.


    That's reasonable, but unless I read it incorrectly, it circles back around
    to being a VBScript need.


    > ...As for why you want to instantiante Excel from ASP, some
    > developer use Excel as a dynamic graphing engine. Please note,
    > I am not one of them. For dynamic graphing I use Office Web
    > Components (OWC).


    In that case, I'll concede that "bad practices" can necessitate this type of
    compensation.


    > No, delete is a documented and supported part of JScript:
    > http://msdn.microsoft.com/library/en-us/script56/html/js56jsoprdelete.asp


    Ah - I never thought to look in the operators section. I see it is also in
    ECMA-262.

    > However, delete has no effect on garbage collection, so it is not
    > relevant to this discussion.


    As for relevance, MS documents it this way:
    http://support.microsoft.com/support/kb/articles/Q229/6/93.asp

    // Destroy and de-reference enumerator object
    delete objEnum;
    objEnum = null;

    That would appear on its surface to have quite a bit to do with garbage
    collection, though I have never seen anything that supports this notion more
    strongly than the above comment.

    From reading the description of the delete operator, I gather that using it
    in the above manner does nothing more than (a) remove it from the global
    namespace, and (b) put it back, this time with a null value. Am I correct?
    Was this just an example of JScript written by a VBScript programmer?


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 23, 2003
    #14
  15. "Dave Anderson" <> wrote in message
    news:%...
    > "Chris Hohmann" wrote:
    > >
    > > I should have been clear. I meant do a Google GROUPS search. Here's

    the
    > > first thread that comes up:
    > >

    http://groups.google.com/groups?threadm=#Lbpzjeu$GA.129@cppssbbsa03
    >
    > OK - I'll grant that some COM objects may occasionally need a property

    set
    > to Nothing or have Nothing passed as a parameter to a method. That is

    a
    > limitation of particular objects that cannot be avoided. But that

    isn't at
    > all the same as assigning Nothing to a variable to "free resources".


    I am unclear on what the difference is. As I understand it, setting a
    COM object or one of its methods/properties does free resources. Could
    you clarify this point.


    > Recall my original objection was to this:
    >
    > "...if you set the recordset to NOTHING as soon as you're
    > done with it that should free those resources up..."
    >
    > And while my assertion regarding the lack of MEANS was incorrect, I

    remain
    > unconvinced that the rest of my response was in error.


    I am unsure what I can do to convince you.


    > Re-reading this thread, I can see where you might think I'm just being
    > argumentative. But I really have a concern here, since we have so many
    > scripts written in JScript that do not use many of the practices

    suggested
    > here (assigning null or Nothing, using disconnected recordsets, etc.).

    If I
    > am splitting hairs, I am doing so to get as much clarity as possible.

    I want
    > my solutions to be robust, and so far they appear to be, but some of

    the
    > claims made here challenge that notion.


    I enjoy a good argument as much as the next fellow and striving to
    produce robust solutions is laudible. I propose that robust solutions in
    JScript should include methodologies to access/use Nothing
    (VT_DISPATCH).


    > > ...If I don't have access to Nothing (VT_DISPATCH) then I cannot
    > > interact with objects that expect to be passed the Nothing value.
    > > Object that fall in this category include ADO.Recordsets and COM
    > > objects which do not implement a custom method to call the
    > > Release() function and instead rely upon the behavior of Nothing
    > > under VBScript to release resources.

    >
    > That's reasonable, but unless I read it incorrectly, it circles back

    around
    > to being a VBScript need.


    Actually, it is the exact opposite. This argument is strictly about a
    need in JScript. JScript has no native support for Nothing. How's that
    for a double negative?


    > > ...As for why you want to instantiante Excel from ASP, some
    > > developer use Excel as a dynamic graphing engine. Please note,
    > > I am not one of them. For dynamic graphing I use Office Web
    > > Components (OWC).

    >
    > In that case, I'll concede that "bad practices" can necessitate this

    type of
    > compensation.


    Actually, any component that relies on the behaviour of
    Nothing(VT_DISPATCH) is suceptible, regardless of whether their use in
    ASP is considered "bad practice".


    > > No, delete is a documented and supported part of JScript:
    > >

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsoprdelete.asp
    >
    > Ah - I never thought to look in the operators section. I see it is

    also in
    > ECMA-262.
    >
    > > However, delete has no effect on garbage collection, so it is not
    > > relevant to this discussion.

    >
    > As for relevance, MS documents it this way:
    > http://support.microsoft.com/support/kb/articles/Q229/6/93.asp
    >
    > // Destroy and de-reference enumerator object
    > delete objEnum;
    > objEnum = null;
    >
    > That would appear on its surface to have quite a bit to do with

    garbage
    > collection, though I have never seen anything that supports this

    notion more
    > strongly than the above comment.
    >
    > From reading the description of the delete operator, I gather that

    using it
    > in the above manner does nothing more than (a) remove it from the

    global
    > namespace, and (b) put it back, this time with a null value. Am I

    correct?
    > Was this just an example of JScript written by a VBScript programmer?


    OK, let me rephrase. Delete does not alter the behavior of garbage
    collection. I was distinguishing it from GarbageCollect() which does.
    Your interpretation of the code seems valid. I have no insight to offer
    on the origin of the code or the coders expertise in JScript.

    -Chris
     
    Chris Hohmann, Sep 23, 2003
    #15
  16. [originally posted yesterday, but after 24 hours, has not shown up on the MS
    server, nor in the Google USENET Archive]

    "Chris Hohmann" wrote:
    >>
    >> ...that isn't at all the same as assigning Nothing to
    >> a variable to "free resources".

    >
    > I am unclear on what the difference is. As I understand it,
    > setting a COM object or one of its methods/properties does
    > free resources. Could you clarify this point.


    I assume you mean setting it/them to Nothing. With that in mind, consider
    the following:

    var RS = Server.CreateObject('ADODB.Recordset')
    var Nothing = RS.ActiveConnection

    Which of the following statements "frees more resources" in JScript?

    1. RS = Nothing
    2. RS = null
    3. delete RS
    4. // Nothing at all

    Answer? Ultimately none, since GC takes care of the job. In the short term,
    #3 probably leads by a trivial margin, since it seems to boot RS out of the
    namespace, but pointers to the original object remain until GC, which you
    supposedly cannot trigger yourself (short of using GarbageCollect(), which
    is strongly discouraged).

    I guess my focus has been on the mischaracterization that you can trigger GC
    with a Nothing assignment in JScript.


    > I propose that robust solutions in JScript should include
    > methodologies to access/use Nothing (VT_DISPATCH).


    And I would counter-propose that robust solutions need not use Nothing
    superfluously, as in the suggestion that triggered this whole discussion.


    > JScript has no native support for Nothing. How's that for a
    > double negative?


    Not only that, but it has no native support for Something or Anything. What
    good is it?


    >> In that case, I'll concede that "bad practices" can necessitate
    >> this type of compensation.

    >
    > Actually, any component that relies on the behaviour of
    > Nothing(VT_DISPATCH) is suceptible, regardless of whether
    > their use in ASP is considered "bad practice".


    I was referring to the server-side instantiation of Excel (and similar
    attempts to use components not optimized for use by a service), not to the
    use of objects needing access to Nothing.


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 25, 2003
    #16
  17. "Dave Anderson" <> wrote in message
    news:%...
    > [originally posted yesterday, but after 24 hours, has not shown up on

    the MS
    > server, nor in the Google USENET Archive]
    >
    > "Chris Hohmann" wrote:
    > >>
    > >> ...that isn't at all the same as assigning Nothing to
    > >> a variable to "free resources".

    > >
    > > I am unclear on what the difference is. As I understand it,
    > > setting a COM object or one of its methods/properties does
    > > free resources. Could you clarify this point.

    >
    > I assume you mean setting it/them to Nothing. With that in mind,

    consider
    > the following:


    Yes, sorry about that.

    > var RS = Server.CreateObject('ADODB.Recordset')
    > var Nothing = RS.ActiveConnection
    >
    > Which of the following statements "frees more resources" in JScript?
    >
    > 1. RS = Nothing
    > 2. RS = null
    > 3. delete RS
    > 4. // Nothing at all
    >
    > Answer? Ultimately none, since GC takes care of the job. In the short

    term,
    > #3 probably leads by a trivial margin, since it seems to boot RS out

    of the
    > namespace, but pointers to the original object remain until GC, which

    you
    > supposedly cannot trigger yourself (short of using GarbageCollect(),

    which
    > is strongly discouraged).
    >
    > I guess my focus has been on the mischaracterization that you can

    trigger GC
    > with a Nothing assignment in JScript.


    I am not sure how to respond to this, except to say that
    "mischaracterization" carries the connoation of a willful intent to
    deceive, which was not was I was trying to do. But, just for the record,
    the following statement is correct:

    You cannot trigger GC with a Nothing assignment in JScript.


    > > I propose that robust solutions in JScript should include
    > > methodologies to access/use Nothing (VT_DISPATCH).

    >
    > And I would counter-propose that robust solutions need not use Nothing
    > superfluously, as in the suggestion that triggered this whole

    discussion.

    Disconnected recordsets?


    > > JScript has no native support for Nothing. How's that for a
    > > double negative?

    >
    > Not only that, but it has no native support for Something or Anything.

    What
    > good is it?


    Disconnected recordsets?


    > >> In that case, I'll concede that "bad practices" can necessitate
    > >> this type of compensation.

    > >
    > > Actually, any component that relies on the behaviour of
    > > Nothing(VT_DISPATCH) is suceptible, regardless of whether
    > > their use in ASP is considered "bad practice".

    >
    > I was referring to the server-side instantiation of Excel (and similar
    > attempts to use components not optimized for use by a service), not to

    the
    > use of objects needing access to Nothing.


    You only conceded that "bad practices" necessitate this type of
    compensation. I pointed out that any component that expects VT_DISPATCH
    would exhibit this behavior. If you would like to argue whether using
    VT_DISPATCH in service components should be classified as "bad practice"
    I think that should be moved to a new thread.

    -Chris
     
    Chris Hohmann, Sep 26, 2003
    #17
  18. "Chris Hohmann" wrote:
    >
    > I am not sure how to respond to this, except to say that
    > "mischaracterization" carries the connoation of a willful
    > intent to deceive, which was not was I was trying to do.


    I apologize if it was taken as an accusation of willful deceit. That
    connotation was unintended. I am applying "mischaracterization" to the whole
    of my observations -- the KB article that claims to "Destroy and
    de-reference" an object, third party ASP articles (ex:
    http://rtfm.atrax.co.uk/infinitemonkeys/articles/asp/917.asp) in which
    solutions look like VBScript solutions bent into JScript, as well as the
    whole of this thread, in particular dlbjr's message.


    >> And I would counter-propose that robust solutions need not use
    >> Nothing superfluously, as in the suggestion that triggered this
    >> whole discussion.

    >
    > Disconnected recordsets?


    Sure. I'll assert that robust solutions need not use disconnected
    recordsets. In fact, I would not be surprised if disconnected recordset
    offered no advantage whatsoever in an IIS5+/SQL Server/JScript environment.
    Connection pooling is a lot better than it used to be.


    >>> JScript has no native support for Nothing. How's that for a
    >>> double negative?

    >>
    >> Not only that, but it has no native support for Something or
    >> Anything. What good is it?

    >
    > Disconnected recordsets?


    I was making a play on words, and asking what good JScript as it neither
    supports Nothing, Anything, nor Something natively.


    > You only conceded that "bad practices" necessitate this type of
    > compensation.


    Not true. Read the first sentence of that very same response:
    http://tinyurl.com/orq1


    > I pointed out that any component that expects VT_DISPATCH
    > would exhibit this behavior. If you would like to argue
    > whether using VT_DISPATCH in service components should be
    > classified as "bad practice" I think that should be moved
    > to a new thread.


    I never made nor intended that argument.


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 26, 2003
    #18
  19. "Dave Anderson" <> wrote in message
    news:...
    > "Chris Hohmann" wrote:
    > >
    > > I am not sure how to respond to this, except to say that
    > > "mischaracterization" carries the connoation of a willful
    > > intent to deceive, which was not was I was trying to do.

    >
    > I apologize if it was taken as an accusation of willful deceit. That
    > connotation was unintended. I am applying "mischaracterization" to the

    whole
    > of my observations -- the KB article that claims to "Destroy and
    > de-reference" an object, third party ASP articles (ex:
    > http://rtfm.atrax.co.uk/infinitemonkeys/articles/asp/917.asp) in which
    > solutions look like VBScript solutions bent into JScript, as well as

    the
    > whole of this thread, in particular dlbjr's message.


    No harm, no foul. :) As for the article, all I can say is Thank You! I
    wish I had come across this first, we could have probablly save
    ourselves a lot of time. It describes the need to set recordsets to
    Nothing (or null) in JScript so much more adeptly than my admittedly
    clumsy approach. Newly educated, I would like to present the following
    scenario:

    1. Create a recordset
    2. Retreive data (GetString/GetRows)
    3. Close recordset
    4. Set recordset to Nothing(null)
    5. Process rest of page

    The key to all of this is that it is the act of setting the recordset to
    Nothing(or null) that marks it for deletion by the GC. Without this
    step, the recordset is not marked for deletion until it goes out of
    scope, ie.when the page finishes executing. By explicitly setting the
    recordset to Nothing(or null) we are telling the GC to mark the
    recordset for deletion on its next pass. In the above scenario, any
    number of things could trigger the GC during step 5. I'm not sure if
    I've referenced this link before, but here's a link that describes how
    the GC is triggered in JScript:

    http://msdn.microsoft.com/msdnmag/issues/01/05/web/default.aspx


    > >> And I would counter-propose that robust solutions need not use
    > >> Nothing superfluously, as in the suggestion that triggered this
    > >> whole discussion.

    > >
    > > Disconnected recordsets?

    >
    > Sure. I'll assert that robust solutions need not use disconnected
    > recordsets. In fact, I would not be surprised if disconnected

    recordset
    > offered no advantage whatsoever in an IIS5+/SQL Server/JScript

    environment.
    > Connection pooling is a lot better than it used to be.


    I guess we will simple have to agree to disagree. However, with regards
    to the advantages of disconnected recordsets, I refer you again to this
    article (which I wrote, in the interest of fair disclosure).

    http://aspfaq.com/2467

    Specifically, in the pros/cons section of recordset iteration, it
    discusses two (2) scenarios that can be acheive by using recordsets that
    would be difficult if not impossible to achieve via GetRows/GetString.
    This advantage applies equally to disconnected recordset. Disconnected
    recordsets also benefit for the fact that they release their associated
    connections back into the pool earlier in the processing cycle.

    With regards to connection pooling, I agree that is has improved. I am
    unsure in what way that is an argument against disconnected recordsets.
    If anything, disconnected recordsets improve connection pooling since,
    as stated previously, the connection associated with the recordset is
    released back into the pool earlier in the processing cycle.

    > >>> JScript has no native support for Nothing. How's that for a
    > >>> double negative?
    > >>
    > >> Not only that, but it has no native support for Something or
    > >> Anything. What good is it?

    > >
    > > Disconnected recordsets?

    >
    > I was making a play on words, and asking what good JScript as it

    neither
    > supports Nothing, Anything, nor Something natively.


    I obviously missed the joke. When you say "What good is it?" are you
    talking about disconnected recordsets or JScript itself. If you are
    talking about disconnected recordsets, please see above. If you are
    talking about JScript, then those are fighting words! :) I think we both
    agree JScript has many unique stregths. If you are talking about
    something else, please elaborate.

    > > You only conceded that "bad practices" necessitate this type of
    > > compensation.

    >
    > Not true. Read the first sentence of that very same response:
    > http://tinyurl.com/orq1


    OK, just so we are clear. We are in agreement that "bad practices", as
    well as practices that are not categorized as "bad", both necessitate
    this type of compensation. Is that accurate?

    > > I pointed out that any component that expects VT_DISPATCH
    > > would exhibit this behavior. If you would like to argue
    > > whether using VT_DISPATCH in service components should be
    > > classified as "bad practice" I think that should be moved
    > > to a new thread.

    >
    > I never made nor intended that argument.


    OK, my mistake.

    -Chris
     
    Chris Hohmann, Sep 27, 2003
    #19
  20. "Chris Hohmann" wrote:
    >
    > 1. Create a recordset
    > 2. Retreive data (GetString/GetRows)
    > 3. Close recordset


    Agreed so far.


    > 4. Set recordset to Nothing(null)
    > 5. Process rest of page


    Hmmm. Let me respond after a bit. But let's first look at how JScript GC is
    described in the article you reference:

    1. When the script engine is shut down, garbage is collected.
    2. When 256 variants, or more than 64KB of strings, or more
    than 4096 array slots have been allocated, the garbage
    collector sets a flag that says collect soon.
    3. Whenever a new statement is executed or the script debugger
    starts, that flag is checked, and if it is set, a collection
    is done.

    If this is true, then I'm not sure step 4 helps much, since GC *still* needs
    to be triggered by a new statement (I'm assuming the script debugger is not
    being used on the production server, where resources would really be an
    issue). Continuing onward...


    > The key to all of this is that it is the act of setting the
    > recordset to Nothing(or null) that marks it for deletion by the GC.


    Marks *what* exactly? The variable is still in scope, and has been assigned
    a value of null/Nothing. There is nothing in the GC description that
    outlines a process for marking something for deletion. I think it's fair to
    say that loss of scope does the job, but I'm still unaware of any definitive
    MS documentation on the matter. The delete operator is looking more
    legitimate by the day.


    > Without this step, the recordset is not marked for deletion until it
    > goes out of scope, ie.when the page finishes executing.


    Please show me something from MS that offers the complement -- that WITH
    THIS STEP, it *is* marked for deletion. This is exactly the issue I have
    been trying to resolve from day 1.


    > By explicitly setting the recordset to Nothing(or null) we are
    > telling the GC to mark the recordset for deletion on its next
    > pass.


    In VBScript, I agree. In JScript, I await proof, or at least a pursuasive
    argument. It has to be better than "that's the way it's done in VBScript, so
    logic dictates it is the same in JScript".


    > ...here's a link that describes how the GC is triggered in JScript:
    >
    > http://msdn.microsoft.com/msdnmag/issues/01/05/web/default.aspx


    ....and still nothing that describes how an object is MARKED for GC.


    > However, with regards to the advantages of disconnected recordsets,
    > I refer you again to this article...
    >
    > http://aspfaq.com/2467


    The word "disconnected" does not appear in that article. It's a comparison
    of GetString(), GetRows(), and iteration. It does, however, say that with
    iteration the recordset must remain open through the entire processing and
    display cycle. This is incorrect on two measures: (1) there is no display
    cycle, and (2) the code need not be structured so inefficiently. Here's an
    example that improves on your sub-optimal model:

    var a = new Array(), RS = CN.Execute(sql)
    while (!RS.EOF) {
    a.push(
    new myObj(
    RS.Fields(key1).Item,
    RS.Fields(key2).Item,
    ...
    RS.Fields(keyN).Item
    )
    )
    RS.MoveNext()
    }
    RS.Close()
    CN.Close()
    a.sort(mySortFunction)
    ...

    ....later on:

    <A HREF="<%=a.Prop1%>"><%=a.Prop2%></A> ...

    Note that by the time the Response Buffer is flushed, the recordset and
    connection were long ago closed. Note also that the only bit of "processing
    cycle" during which the recordset is open is that bit devoted to building
    and reading the recordset.

    I'm not going to dispute that GetRows() is faster than iteration, but I will
    point out that your article does not compare JScript performance differences
    between them. Is there additional overhead involved in stepping through a
    VBArray Object (especially if a sort is in order)? Is it better to keep a
    VBArray Object in scope than a Recordset Object? Give me a few days, and
    I'll run a test on it, then perhaps offer an article to Aaron.


    > If anything, disconnected recordsets improve connection
    > pooling since, as stated previously, the connection
    > associated with the recordset is released back into the
    > pool earlier in the processing cycle.


    I would like to know if that is indeed true. It is almost certainly true
    that closing the connection improves pooling performance.


    > If you are talking about JScript, then those are fighting words!


    I was, but only jokingly. JScript is way too cool to use anything else for
    routine ASP tasks.


    > OK, just so we are clear. We are in agreement that "bad
    > practices", as well as practices that are not categorized
    > as "bad", both necessitate this type of compensation. Is
    > that accurate?


    Yes.


    --
    Dave Anderson

    Unsolicited commercial email will be read at a cost of $500 per message. Use
    of this email address implies consent to these terms. Please do not contact
    me directly or ask me to contact you directly for assistance. If your
    question is worth asking, it's worth posting.
     
    Dave Anderson, Sep 29, 2003
    #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. Replies:
    3
    Views:
    462
    Mike Treseler
    Mar 8, 2006
  2. Christoph Brunner
    Replies:
    13
    Views:
    910
  3. Michael
    Replies:
    4
    Views:
    466
    Matt Hammond
    Jun 26, 2006
  4. Replies:
    7
    Views:
    352
  5. Robert Klemme

    With a Ruby Yell: more, more more!

    Robert Klemme, Sep 28, 2005, in forum: Ruby
    Replies:
    5
    Views:
    236
    Jeff Wood
    Sep 29, 2005
Loading...

Share This Page