getting rid of dependency of default values

Discussion in 'C++' started by asianmuscle@gmail.com, Sep 26, 2006.

  1. Guest

    I am trying to learn RAII and some template techniques by writer a
    smarter pointer class to manage the resource management. Since I find
    that a lot of the resource management is kinda the same, I try to mimic
    some other examples outther then tailor to my needs. My case is for
    windows handle like hkey, dll library, file handle, etc. But the code
    largely uses standard C++. Only the Clean up action, I put windows api
    call in there.
    In general, I want to archieve one thing: the template will instantiate
    when I give it the inpout type, then call the CloseResource eventually
    to clean up on exit of scope.

    But I have a hard time to make the class to find out what the
    NULL_VALUE is. NULL_VALUE is a value that depends on the type. or is
    this a worthwhile effort to get rid of that dependency?I defaulted
    evertyhing to NULL now but not all type will default to NULL, if I take
    extendsibility into account.

    Also I notice I end up with a lot of small policy classes. Is there a
    way to reduce that number? Because all it depends is the windows API
    call. I think I am asking somethign circular here. Thanks. See below
    for code:

    For the release policy code:
    #include <windows.h>

    template <typename hType>
    struct RegistryPolicy{
    void CloseResource(hType& h){
    ::RegCloseKey(h);
    h=NULL; //?
    };

    protected: // do I need these or delete those? they are compiler
    generated anyway
    RegistryPolicy(){};
    ~RegistryPolicy(){};
    private:
    RegistryPolicy(RegistryPolicy&);
    RegistryPolicy& operator=(RegistryPolicy&);
    };

    template <typename hType>
    struct LibraryPolicy{
    void CloseResource(hType& h){
    ::FreeLibrary(h);
    h=NULL; //?
    };
    protected:
    LibraryPolicy(){};
    ~LibraryPolicy(){};
    private:
    explicit LibraryPolicy(LibraryPolicy&);
    LibraryPolicy& operator=(LibraryPolicy&);
    };


    template <typename hType>
    struct CloseViewOfFile{
    void CloseResource(hType& h){
    ::UnmapViewOfFile(h);
    h=NULL; //?
    };
    protected:
    explicit CloseViewOfFile(){};
    ~CloseViewOfFile(){};
    private:
    CloseViewOfFile(CloseViewOfFile&);
    CloseViewOfFile& operator=(CloseViewOfFile&);

    };
    ///////////////////////////// my smarter pointer code in below
    //////////////////////////////
    template <class T>
    void DestroyObject(T object) {object->Destroy();}

    template <class T>
    void DesposeObject(T object) {object->CloseResource();}

    //
    //

    template <typename hType,
    template<typename> class ReleasePolicy=DeposeObject,
    hType NULL_VALUE=NULL> //how to generalize NULL_VALUE? make it
    get the value depending on the type?
    class SmarterHolder{
    private:
    hType mhandle;

    void CleanUp(){
    if (NULL_VALUE!= mhandle)
    {
    ReleasePolicy(mhandle);
    mhandle = NULL_VALUE;
    }
    }
    hType operator=(hType);
    SmarterHolder(SmarterHolder&);

    public:
    explicit SmarterHolder():mhandle(NULL_VALUE){};
    explicit SmarterHolder(hType h): mhandle(h){};
    ~SmarterHolder(){ ReleasePolicy(); };
    operator hType () const { return mhandle; }
    bool IsValidHandle() const { return NULL_VALUE != mhandle; }

    };
    #endif
    , Sep 26, 2006
    #1
    1. Advertising

  2. mlimber Guest

    wrote:
    > I am trying to learn RAII and some template techniques by writer a
    > smarter pointer class to manage the resource management. Since I find
    > that a lot of the resource management is kinda the same, I try to mimic
    > some other examples outther then tailor to my needs. My case is for
    > windows handle like hkey, dll library, file handle, etc. But the code
    > largely uses standard C++. Only the Clean up action, I put windows api
    > call in there.
    > In general, I want to archieve one thing: the template will instantiate
    > when I give it the inpout type, then call the CloseResource eventually
    > to clean up on exit of scope.
    >
    > But I have a hard time to make the class to find out what the
    > NULL_VALUE is. NULL_VALUE is a value that depends on the type. or is
    > this a worthwhile effort to get rid of that dependency?I defaulted
    > evertyhing to NULL now but not all type will default to NULL, if I take
    > extendsibility into account.


    See below.

    > Also I notice I end up with a lot of small policy classes. Is there a
    > way to reduce that number? Because all it depends is the windows API
    > call. I think I am asking somethign circular here.


    Some existing implementations of smart pointers (e.g.,
    std::tr1::shared_ptr aka boost::shared_ptr) accept a deleter argument.
    That would suffice in a case such as this:

    struct SomeHandle { /*...*/ };
    SomeHandle* GetResource();
    void FreeResource( SomeHandle* );

    std::tr1::shared_ptr<SomeHandle> handle(
    GetResource(), FreeResource );

    You could also use boost::bind or boost::lambda to reduce the number of
    simple policies (probably not a good idea if they are used more than
    once).

    > For the release policy code:
    > #include <windows.h>
    >
    > template <typename hType>
    > struct RegistryPolicy{
    > void CloseResource(hType& h){
    > ::RegCloseKey(h);
    > h=NULL; //?


    Setting to NULL is probably unnecessary if you're using smart pointers
    since the smart pointer is entirely responsible for the resource and
    will only call on the release policy when the item is being destroyed
    (either on destruction or reset).

    > };


    Semicolons are not necessary after function definitions. You should
    also make this function static since there is no member data in play
    here.

    >
    > protected: // do I need these or delete those? they are compiler
    > generated anyway
    > RegistryPolicy(){};
    > ~RegistryPolicy(){};


    They would be generated public by default. You must define them
    yourself to override that.

    > private:
    > RegistryPolicy(RegistryPolicy&);
    > RegistryPolicy& operator=(RegistryPolicy&);


    The function parameter should be const in both cases.

    > };
    >
    > template <typename hType>
    > struct LibraryPolicy{
    > void CloseResource(hType& h){
    > ::FreeLibrary(h);
    > h=NULL; //?
    > };
    > protected:
    > LibraryPolicy(){};
    > ~LibraryPolicy(){};
    > private:
    > explicit LibraryPolicy(LibraryPolicy&);
    > LibraryPolicy& operator=(LibraryPolicy&);
    > };
    >
    >
    > template <typename hType>
    > struct CloseViewOfFile{
    > void CloseResource(hType& h){
    > ::UnmapViewOfFile(h);
    > h=NULL; //?
    > };
    > protected:
    > explicit CloseViewOfFile(){};
    > ~CloseViewOfFile(){};
    > private:
    > CloseViewOfFile(CloseViewOfFile&);
    > CloseViewOfFile& operator=(CloseViewOfFile&);
    >
    > };
    > ///////////////////////////// my smarter pointer code in below
    > //////////////////////////////
    > template <class T>
    > void DestroyObject(T object) {object->Destroy();}
    >
    > template <class T>
    > void DesposeObject(T object) {object->CloseResource();}


    Dispose?

    >
    > //
    > //
    >
    > template <typename hType,
    > template<typename> class ReleasePolicy=DeposeObject,


    DisposeObject?

    > hType NULL_VALUE=NULL>//how to generalize NULL_VALUE? makeit
    > get the value depending on the type?


    Use the default value of hType:

    template
    <
    typename hType,
    template<typename> class ReleasePolicy=DisposeObject,
    hType NULL_VALUE=hType()
    >

    class SmartHolder;

    > class SmarterHolder{
    > private:
    > hType mhandle;
    >
    > void CleanUp(){
    > if (NULL_VALUE!= mhandle)
    > {
    > ReleasePolicy(mhandle);
    > mhandle = NULL_VALUE;
    > }
    > }
    > hType operator=(hType);
    > SmarterHolder(SmarterHolder&);
    >
    > public:
    > explicit SmarterHolder():mhandle(NULL_VALUE){};
    > explicit SmarterHolder(hType h): mhandle(h){};
    > ~SmarterHolder(){ ReleasePolicy(); };
    > operator hType () const { return mhandle; }
    > bool IsValidHandle() const { return NULL_VALUE != mhandle; }
    > };
    > #endif


    I'd suggest that, rather than rolling your own, you should switch to
    using a tried-and-true RAII mechanism like std::tr1::/boost::shared_ptr
    (where you would supply a custom deleter) or even Loki::SmartPtr (where
    you would supply a storage policy). No need to reinvent the wheel.

    Cheers! --M
    mlimber, Sep 26, 2006
    #2
    1. Advertising

  3. Guest

    Hi, thanks for your feedback. I learnt quite something by reading your
    reply. The reason of making this is an exercise for me to learn more on
    using template. My C++ is kinda shaky after 4 yrs of idle.
    In reply to DisposeObject below. What I intended as to let
    SmarterHandle to call the the "Policy template class" such that, the
    call will dispatch to the appropriate CleanResource. The idea was to
    let the function template DisposeObject right above smarterhandle, then
    which in turn defer to the policy class. I note that all the example I
    see on theweb have SmarterHandle to inherit from ReleasePolicy to get
    access to
    CloseResource. But I just don't get why it has to inherit. so instead I
    just try to do a usage here. But I can see there is something not going
    right with my current arrangement. Can you help me a bit on that. I
    don't think my C++ skills is good enough to concretly pinpoint that.
    Thanks


    mlimber wrote:
    > wrote:
    > > I am trying to learn RAII and some template techniques by writer a
    > > smarter pointer class to manage the resource management. Since I find
    > > that a lot of the resource management is kinda the same, I try to mimic
    > > some other examples outther then tailor to my needs. My case is for
    > > windows handle like hkey, dll library, file handle, etc. But the code
    > > largely uses standard C++. Only the Clean up action, I put windows api
    > > call in there.
    > > In general, I want to archieve one thing: the template will instantiate
    > > when I give it the inpout type, then call the CloseResource eventually
    > > to clean up on exit of scope.
    > >
    > > But I have a hard time to make the class to find out what the
    > > NULL_VALUE is. NULL_VALUE is a value that depends on the type. or is
    > > this a worthwhile effort to get rid of that dependency?I defaulted
    > > evertyhing to NULL now but not all type will default to NULL, if I take
    > > extendsibility into account.

    >
    > See below.
    >
    > > Also I notice I end up with a lot of small policy classes. Is there a
    > > way to reduce that number? Because all it depends is the windows API
    > > call. I think I am asking somethign circular here.

    >
    > Some existing implementations of smart pointers (e.g.,
    > std::tr1::shared_ptr aka boost::shared_ptr) accept a deleter argument.
    > That would suffice in a case such as this:
    >
    > struct SomeHandle { /*...*/ };
    > SomeHandle* GetResource();
    > void FreeResource( SomeHandle* );
    >
    > std::tr1::shared_ptr<SomeHandle> handle(
    > GetResource(), FreeResource );
    >
    > You could also use boost::bind or boost::lambda to reduce the number of
    > simple policies (probably not a good idea if they are used more than
    > once).
    >
    > > For the release policy code:
    > > #include <windows.h>
    > >
    > > template <typename hType>
    > > struct RegistryPolicy{
    > > void CloseResource(hType& h){
    > > ::RegCloseKey(h);
    > > h=NULL; //?

    >
    > Setting to NULL is probably unnecessary if you're using smart pointers
    > since the smart pointer is entirely responsible for the resource and
    > will only call on the release policy when the item is being destroyed
    > (either on destruction or reset).
    >
    > > };

    >
    > Semicolons are not necessary after function definitions. You should
    > also make this function static since there is no member data in play
    > here.
    >
    > >
    > > protected: // do I need these or delete those? they are compiler
    > > generated anyway
    > > RegistryPolicy(){};
    > > ~RegistryPolicy(){};

    >
    > They would be generated public by default. You must define them
    > yourself to override that.
    >
    > > private:
    > > RegistryPolicy(RegistryPolicy&);
    > > RegistryPolicy& operator=(RegistryPolicy&);

    >
    > The function parameter should be const in both cases.
    >
    > > };
    > >
    > > template <typename hType>
    > > struct LibraryPolicy{
    > > void CloseResource(hType& h){
    > > ::FreeLibrary(h);
    > > h=NULL; //?
    > > };
    > > protected:
    > > LibraryPolicy(){};
    > > ~LibraryPolicy(){};
    > > private:
    > > explicit LibraryPolicy(LibraryPolicy&);
    > > LibraryPolicy& operator=(LibraryPolicy&);
    > > };
    > >
    > >
    > > template <typename hType>
    > > struct CloseViewOfFile{
    > > void CloseResource(hType& h){
    > > ::UnmapViewOfFile(h);
    > > h=NULL; //?
    > > };
    > > protected:
    > > explicit CloseViewOfFile(){};
    > > ~CloseViewOfFile(){};
    > > private:
    > > CloseViewOfFile(CloseViewOfFile&);
    > > CloseViewOfFile& operator=(CloseViewOfFile&);
    > >
    > > };
    > > ///////////////////////////// my smarter pointer code in below
    > > //////////////////////////////
    > > template <class T>
    > > void DestroyObject(T object) {object->Destroy();}
    > >
    > > template <class T>
    > > void DesposeObject(T object) {object->CloseResource();}

    >
    > Dispose?
    >
    > >
    > > //
    > > //
    > >
    > > template <typename hType,
    > > template<typename> class ReleasePolicy=DeposeObject,

    >
    > DisposeObject?
    >
    > > hType NULL_VALUE=NULL>//how to generalize NULL_VALUE? makeit
    > > get the value depending on the type?

    >
    > Use the default value of hType:
    >
    > template
    > <
    > typename hType,
    > template<typename> class ReleasePolicy=DisposeObject,
    > hType NULL_VALUE=hType()
    > >

    > class SmartHolder;
    >
    > > class SmarterHolder{
    > > private:
    > > hType mhandle;
    > >
    > > void CleanUp(){
    > > if (NULL_VALUE!= mhandle)
    > > {
    > > ReleasePolicy(mhandle);
    > > mhandle = NULL_VALUE;
    > > }
    > > }
    > > hType operator=(hType);
    > > SmarterHolder(SmarterHolder&);
    > >
    > > public:
    > > explicit SmarterHolder():mhandle(NULL_VALUE){};
    > > explicit SmarterHolder(hType h): mhandle(h){};
    > > ~SmarterHolder(){ ReleasePolicy(); };
    > > operator hType () const { return mhandle; }
    > > bool IsValidHandle() const { return NULL_VALUE != mhandle; }
    > > };
    > > #endif

    >
    > I'd suggest that, rather than rolling your own, you should switch to
    > using a tried-and-true RAII mechanism like std::tr1::/boost::shared_ptr
    > (where you would supply a custom deleter) or even Loki::SmartPtr (where
    > you would supply a storage policy). No need to reinvent the wheel.
    >
    > Cheers! --M
    , Sep 26, 2006
    #3
  4. Peter Guest

    wrote:
    > I am trying to learn RAII and some template techniques by writer a


    I don't fully understand why you need templates here.
    I usually write one class for every way I can allocate a system
    resource.
    E.g. LoadLibrary belongs in the constructor and FreeLibrary into the
    destructor.
    E.g. RegCreateKey belongs into the constructor and RegCloseKey() into
    the destructor.
    If allocation fails throw an an exception containing the full error
    information -- e.g. GetLastError()
    -- what() should then return the system error message -- using
    FormatMessage() I think.

    The same applies for other operating systems.
    Peter, Sep 27, 2006
    #4
  5. Peter Guest

    wrote:
    > I am trying to learn RAII and some template techniques by writer a


    I don't fully understand why you need templates here.
    I usually write one class for every way I can allocate a system
    resource.
    E.g. LoadLibrary belongs in the constructor and FreeLibrary into the
    destructor.
    E.g. RegCreateKey belongs into the constructor and RegCloseKey() into
    the destructor.
    If allocation fails throw an an exception containing the full error
    information -- e.g. GetLastError()
    -- what() should then return the system error message -- using
    FormatMessage() I think.

    The same applies for other operating systems.
    Peter, Sep 27, 2006
    #5
  6. mlimber Guest

    wrote:
    > mlimber wrote:
    > > wrote:
    > > > I am trying to learn RAII and some template techniques by writer a
    > > > smarter pointer class to manage the resource management. Since I find
    > > > that a lot of the resource management is kinda the same, I try to mimic
    > > > some other examples outther then tailor to my needs. My case is for
    > > > windows handle like hkey, dll library, file handle, etc. But the code
    > > > largely uses standard C++. Only the Clean up action, I put windows api
    > > > call in there.
    > > > In general, I want to archieve one thing: the template will instantiate
    > > > when I give it the inpout type, then call the CloseResource eventually
    > > > to clean up on exit of scope.
    > > >
    > > > But I have a hard time to make the class to find out what the
    > > > NULL_VALUE is. NULL_VALUE is a value that depends on the type. or is
    > > > this a worthwhile effort to get rid of that dependency?I defaulted
    > > > evertyhing to NULL now but not all type will default to NULL, if I take
    > > > extendsibility into account.

    > >
    > > See below.
    > >
    > > > Also I notice I end up with a lot of small policy classes. Is there a
    > > > way to reduce that number? Because all it depends is the windows API
    > > > call. I think I am asking somethign circular here.

    > >
    > > Some existing implementations of smart pointers (e.g.,
    > > std::tr1::shared_ptr aka boost::shared_ptr) accept a deleter argument.
    > > That would suffice in a case such as this:
    > >
    > > struct SomeHandle { /*...*/ };
    > > SomeHandle* GetResource();
    > > void FreeResource( SomeHandle* );
    > >
    > > std::tr1::shared_ptr<SomeHandle> handle(
    > > GetResource(), FreeResource );
    > >
    > > You could also use boost::bind or boost::lambda to reduce the number of
    > > simple policies (probably not a good idea if they are used more than
    > > once).
    > >
    > > > For the release policy code:
    > > > #include <windows.h>
    > > >
    > > > template <typename hType>
    > > > struct RegistryPolicy{
    > > > void CloseResource(hType& h){
    > > > ::RegCloseKey(h);
    > > > h=NULL; //?

    > >
    > > Setting to NULL is probably unnecessary if you're using smart pointers
    > > since the smart pointer is entirely responsible for the resource and
    > > will only call on the release policy when the item is being destroyed
    > > (either on destruction or reset).
    > >
    > > > };

    > >
    > > Semicolons are not necessary after function definitions. You should
    > > also make this function static since there is no member data in play
    > > here.
    > >
    > > >
    > > > protected: // do I need these or delete those? they are compiler
    > > > generated anyway
    > > > RegistryPolicy(){};
    > > > ~RegistryPolicy(){};

    > >
    > > They would be generated public by default. You must define them
    > > yourself to override that.
    > >
    > > > private:
    > > > RegistryPolicy(RegistryPolicy&);
    > > > RegistryPolicy& operator=(RegistryPolicy&);

    > >
    > > The function parameter should be const in both cases.
    > >
    > > > };
    > > >
    > > > template <typename hType>
    > > > struct LibraryPolicy{
    > > > void CloseResource(hType& h){
    > > > ::FreeLibrary(h);
    > > > h=NULL; //?
    > > > };
    > > > protected:
    > > > LibraryPolicy(){};
    > > > ~LibraryPolicy(){};
    > > > private:
    > > > explicit LibraryPolicy(LibraryPolicy&);
    > > > LibraryPolicy& operator=(LibraryPolicy&);
    > > > };
    > > >
    > > >
    > > > template <typename hType>
    > > > struct CloseViewOfFile{
    > > > void CloseResource(hType& h){
    > > > ::UnmapViewOfFile(h);
    > > > h=NULL; //?
    > > > };
    > > > protected:
    > > > explicit CloseViewOfFile(){};
    > > > ~CloseViewOfFile(){};
    > > > private:
    > > > CloseViewOfFile(CloseViewOfFile&);
    > > > CloseViewOfFile& operator=(CloseViewOfFile&);
    > > >
    > > > };
    > > > ///////////////////////////// my smarter pointer code in below
    > > > //////////////////////////////
    > > > template <class T>
    > > > void DestroyObject(T object) {object->Destroy();}
    > > >
    > > > template <class T>
    > > > void DesposeObject(T object) {object->CloseResource();}

    > >
    > > Dispose?
    > >
    > > >
    > > > //
    > > > //
    > > >
    > > > template <typename hType,
    > > > template<typename> class ReleasePolicy=DeposeObject,

    > >
    > > DisposeObject?
    > >
    > > > hType NULL_VALUE=NULL>//how to generalize NULL_VALUE? makeit
    > > > get the value depending on the type?

    > >
    > > Use the default value of hType:
    > >
    > > template
    > > <
    > > typename hType,
    > > template<typename> class ReleasePolicy=DisposeObject,
    > > hType NULL_VALUE=hType()
    > > >

    > > class SmartHolder;
    > >
    > > > class SmarterHolder{
    > > > private:
    > > > hType mhandle;
    > > >
    > > > void CleanUp(){
    > > > if (NULL_VALUE!= mhandle)
    > > > {
    > > > ReleasePolicy(mhandle);
    > > > mhandle = NULL_VALUE;
    > > > }
    > > > }
    > > > hType operator=(hType);
    > > > SmarterHolder(SmarterHolder&);
    > > >
    > > > public:
    > > > explicit SmarterHolder():mhandle(NULL_VALUE){};
    > > > explicit SmarterHolder(hType h): mhandle(h){};
    > > > ~SmarterHolder(){ ReleasePolicy(); };
    > > > operator hType () const { return mhandle; }
    > > > bool IsValidHandle() const { return NULL_VALUE != mhandle; }
    > > > };
    > > > #endif

    > >
    > > I'd suggest that, rather than rolling your own, you should switch to
    > > using a tried-and-true RAII mechanism like std::tr1::/boost::shared_ptr
    > > (where you would supply a custom deleter) or even Loki::SmartPtr (where
    > > you would supply a storage policy). No need to reinvent the wheel.
    > >
    > > Cheers! --M

    >


    First, please don't top-post here (see
    http://parashift.com/c -faq-lite/how-to-post.html#faq-5.4). I fixed it
    for you in this reply.

    > Hi, thanks for your feedback. I learnt quite something by reading your
    > reply. The reason of making this is an exercise for me to learn more on
    > using template. My C++ is kinda shaky after 4 yrs of idle.


    You should pick up _Accelerated C++_ by Koenig and Moo. It's great for
    re-learning C++ the right way. Also, you might be interested in _Modern
    C++ Design_ by Alexandrescu. You can see his chapter on smart pointers
    here for free:

    http://www.informit.com/articles/printerfriendly.asp?p=25264&rl=1

    > In reply to DisposeObject below. What I intended as to let
    > SmarterHandle to call the the "Policy template class" such that, the
    > call will dispatch to the appropriate CleanResource. The idea was to
    > let the function template DisposeObject right above smarterhandle, then
    > which in turn defer to the policy class. I note that all the example I
    > see on theweb have SmarterHandle to inherit from ReleasePolicy to get
    > access to
    > CloseResource. But I just don't get why it has to inherit. so instead I
    > just try to do a usage here. But I can see there is something not going
    > right with my current arrangement. Can you help me a bit on that. I
    > don't think my C++ skills is good enough to concretly pinpoint that.


    Inheritance is sometimes required if you want to build an interface
    from policies. For instance:

    struct A
    {
    static void f1() { /*...*/ }
    void f2() { /*...*/ }
    };

    struct B
    {
    static void f3() { /*...*/ }
    };

    template<class Policy1, class Policy2>
    struct C : Policy1
    {
    C()
    {
    f1();
    f2();
    Policy2::f3();
    }
    };

    typedef C<A,B> D;

    void Foo( D& d )
    {
    D::f1(); // Ok
    d.f2(); // Ok
    D::f3(); // Error!
    }

    Notice that while D has no member functions of its own (other than the
    constructor), it inherits some from its Policy1 template parameter and
    it can internally use those of its Policy2 template parameter. In
    general, you should not inherit unless you need to (cf.
    http://www.parashift.com/c -faq-lite/private-inheritance.html#faq-24.3).

    Cheers! --M
    mlimber, Sep 27, 2006
    #6
    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. damonf
    Replies:
    2
    Views:
    2,447
    damonf
    Nov 8, 2003
  2. dario

    getting rid of params in url

    dario, Feb 20, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    315
    dario
    Feb 20, 2004
  3. Daniel Michaeloff

    Getting rid of session cookie ("ASP.NET_SessionId")

    Daniel Michaeloff, Dec 8, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    9,599
    Hans Kesting
    Dec 9, 2004
  4. Replies:
    5
    Views:
    11,011
    I82Much
    Jun 3, 2009
  5. kaush
    Replies:
    0
    Views:
    147
    kaush
    Oct 12, 2005
Loading...

Share This Page