SitePoint Sponsor

User Tag List

Results 1 to 21 of 21
  1. #1
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Talking MVC ... I *think* I'm almost there... almost!

    1) Client requests page.

    2) Front Controller is invoked from client’s request.

    3) Front Controller initiates the Filter Manager, which adds Filters into the Filter Chain.

    4) Front Controller then moves over to the Application Controller.

    5) The Application Controller initiates the ActionMapper, which uses Maps to define which Command Controller to use.

    6) The application Controller, now armed with a request map, initiates the custom Command Controller (e.g. news).

    7) NewsController runs necessary code (MySQL etc.), and creates a ViewController.

    8) ViewController, armed with ViewHelpers, creates Browser Code (HTML, etc).

    9) ViewController, then outputs to the browser.




    Thus far, this is my interpretation of MVC.

    I understand each to their own (somewhat) with MVC since it's only a design pattern, however just a few questions which I’d appreciate some feedback on please.




    I would like to use the Filters mainly, and only, for pre & post auditing - by this I mean:

    a) I want to be able to securely pass all data that's not been hard coded ($_POST, $_GET, $_COOKIE, $_SERVER) through a filter, to sanitise it.


    I personally believe this should be done through a filter, but thinking and reading closer... a Request Handler should be used.

    If I was to use a Request Handler (checking magic_quotes, etc), where in the list from 1-9 should this ideally be included, or should this just be a filter?

    b) If I want to be able to Post Filter data, i.e. Response Handler, to GZIP/Encrypt, should this be added as a filter of a Response Handler, if so, which number should it ideally appear in the list?




    My feelings are that it should be around #9, which doesn't feel 100% right, which leads me onto my next question....

    I've read up on Dispatchers, what they do in my eyes is a bit sketchy, do they mean and could they be used in this context:

    ... Between #6, instead of Application Controller initiating the customer Controller, could we change the points to say:

    5) The Application Controller initiates the RequestHandler.

    6) The Application Controller initiates the ActionMapper with the output from RequestHandler, which uses Maps to process URI/URL.

    7) The Application Controller, now armed with a request Map, initiates the Dispatcher.


    8) The Dispatcher initiates the custom Command Controller (e.g. news) based from the feedback of the Map.

    9) NewsController runs necessary code (MySQL etc.), and creates a ViewController.

    10) ViewController, armed with ViewHelpers, creates Browser Code (HTML, etc).

    11) ViewController, returns back to the custom Controller, which is then passed back to the Dispatcher.

    12) Dispatcher, armed with the Browser Code, initiates Response Handler and outputs to the browser after filters have been run.



    I know that your view of this list might not be what you do, or what you'd want it to do. Personally, this is what I'd need for my application to function 100%, allowing for future expansion.

    However, what I don't want is to start whacking out code only to find that my view of this design has changed and becomes flawed for the purposes originally designed for.


    edit: sp
    Keep life simple... don't put your head through plexiglass.

  2. #2
    SitePoint Zealot Serberus's Avatar
    Join Date
    Oct 2005
    Location
    Herts, UK
    Posts
    113
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question

    Looks pretty good to me. Would it hurt to simplify some things in steps 4 - 6?
    4) Front Controller then moves over to the Application Controller.

    5) The Application Controller initiates the ActionMapper, which uses Maps to define which Command Controller to use.

    6) The application Controller, now armed with a request map, initiates the custom Command Controller (e.g. news).
    Could you eliminate the Application Controller and initiate the Request Handler, ActionMapper and Dispatcher from here to instantiate the appropriate Command Controller?

    Or am I missing something by doing this?

    With regards to the Dispatcher, I think this might be it's job:

    PHP Code:
    $className $actionMapper->getCommand();
    $fileName 'app/controllers/'.$className.'.php';

    if (
    file_exists($fileName)) {
        require(
    $fileName);
        
    $controller = new $className();
        
    // or $controller = new $className($requestHandler,$dbLayer); ?
        
      
    if ($controller instanceof iController) {
         
    $controller->execute();
      } else {
         
    // not a controller, redirect to front page?
      
    }
    } else {
        
    // this shouldn't happen


  3. #3
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Serberus
    Looks pretty good to me. Would it hurt to simplify some things in steps 4 - 6?
    Could you eliminate the Application Controller and initiate the Request Handler, ActionMapper and Dispatcher from here to instantiate the appropriate Command Controller?
    Serberus, by this I think you mean completely get rid of the Front Controller initiating the Application Controller and basically combining them?

    I don't think you're missing something, could just be me, but reading as much as I could lay my hands on ApplicationControllers, this seems to be where most code examples/tuts were leading me... but then, I would KISS, although I'll hopefully have some more feedback to weight up if it's worth keeping it as mentioned.


    Quote Originally Posted by Serberus
    With regards to the Dispatcher, I think this might be it's job:

    PHP Code:
    $className $actionMapper->getCommand();
    $fileName 'app/controllers/'.$className.'.php';

    if (
    file_exists($fileName)) {
        require(
    $fileName);
        
    $controller = new $className();
        
    // or $controller = new $className($requestHandler,$dbLayer); ?
        
      
    if ($controller instanceof iController) {
         
    $controller->execute();
      } else {
         
    // not a controller, redirect to front page?
      
    }
    } else {
        
    // this shouldn't happen

    My understanding of this code, is that the Dispatcher is obtaining the full path to the Custom Controller, including it, initiating it, and executing it, providing any errors during runtime if theres no parent class or include errors.

    Isn't that similar to my steps below or am I missing something too?

    Quote Originally Posted by damiengiles
    8) The Dispatcher initiates the custom Command Controller (e.g. news) based from the feedback of the Map.

    9) NewsController runs necessary code (MySQL etc.), and creates a ViewController.

    10) ViewController, armed with ViewHelpers, creates Browser Code (HTML, etc).

    11) ViewController, returns back to the custom Controller, which is then passed back to the Dispatcher.

    12) Dispatcher, armed with the Browser Code, initiates Response Handler and outputs to the browser after filters have been run.
    Thanks for the feedback!
    Last edited by DamienGiles; Apr 15, 2006 at 18:03.
    Keep life simple... don't put your head through plexiglass.

  4. #4
    SitePoint Zealot Serberus's Avatar
    Join Date
    Oct 2005
    Location
    Herts, UK
    Posts
    113
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by DamienGiles
    Serberus, by this I think you mean completely get rid of the Front Controller initiating the Action Controller and basically combining them?
    Did you mean Application Controller instead of Action Controller? If so then yes, it just seems like an extra step and I couldn't see a benefit.

    Quote Originally Posted by DamienGiles
    My understanding of this code, is that the Dispatcher is obtaining the full path to the Custom Controller, including it, initiating it, and executing it, providing any errors during runtime if theres no parent class or include errors.
    Yup.

    Quote Originally Posted by DamienGiles
    Isn't that similar to my steps below or am I missing something too?
    If we're agreed this is what the Dispatcher does (for step 8) then my code only re-enforces what you've already stated, so I think we're singing from the same song sheet so far

    I've not used ViewControllers before, or come back to the Dispatcher like that before sending a response - lack of experience on my part, not questioning your thinking here.

    Would this be an example of a ViewController?

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    FrontController and ApplicationController are words which Martin Fowler have coined. He doesn't use the term dispatcher, but he does say that the "FrontController dispatches to a handler". I think it's safe to assume that most people use the words FrontController and Dispatcher as synonymes.

    The problem you are describing is not related to MVC. MVC is a completely different ballgame, but the confusion is common.
    What you're dealing with here, is the question of how to translate a (HTTP) request into the execution of a block of code (a controller). PHP's native handling of this issue is very crude, and this has let to a lot of tinkering to do it better, often expressed as frameworks. MVC has been used as a buzzword, so people would label their frameworks as MVC-frameworks or MVC-compliant framework or whatever, which has added to the confusion.

    Basically, there are two ways of translating the request. There is a linear translation and there is a context-dependent translation. The first is handled by a FrontController. In PHP, the webserver can be seen as a FrontController, but you can extend the FrontController by having a single entrypoint, which dispatches to other controllers. The reason for doing this is that it allows you to run global code in the FrontController.

    The FrontController is trivial - It will always give the same result, if fed with the same input. An ApplicationController is like a FrontController, in that it dispatches it's control to another controller, but the conditions for the mapping is something more than just the request itself.
    A prime example is a controller for a form; If certain rules are met, the form is valid, and the control should be delegated to an onValid handler. If not, control should be delegated to an onInvalid handler. The part of your code, which does this is an ApplicationController.
    The ApplicationController may itself delegate to another ApplicationController, which means that there may be multiple ApplicationControllers for the same request. Eventually they will reach a controller, which doesn't delegate control further. This end-station will generate a response.

  6. #6
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Serberus
    Did you mean Application Controller instead of Action Controller? If so then yes, it just seems like an extra step and I couldn't see a benefit.
    Yes, sorry.. Controllers have fried my brain after 10hours researching =)

    Quote Originally Posted by Serberus
    If we're agreed this is what the Dispatcher does (for step 8) then my code only re-enforces what you've already stated, so I think we're singing from the same song sheet so far
    Looks like we are, which is a positive step forward for me, I love the feeling when what you've been trying to learn finally CLICKS.

    Quote Originally Posted by Serberus
    I've not used ViewControllers before, or come back to the Dispatcher like that before sending a response - lack of experience on my part, not questioning your thinking here.
    Me too, it just didn't seem logical to have the View output directly to the browser, I suppose it could potentially make sense for the CustomController(news) to initial the ResponseHandler to output after Post-Filters have completed if thats what you mean... that's really the main reason for this thread.

    But then, thinking about it... If I wanted to change the way the Reponse Handler was called, I'd have to modify every CustomController, unless I have the CustomController extend a parent, that define the Outputting Stages, but this seems to break logic in my eyes.

    Quote Originally Posted by Serberus
    Would this be an example of a ViewController?
    I've spent, I would say, close to 2 hours reading that, re reading that, printing it out, reading it, and still only on page 2.

    Seriously though, that's a handy thread which I have tabbed open whilst replying here...
    Keep life simple... don't put your head through plexiglass.

  7. #7
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    kyberfabrikken, your post answered many of my unanswered questions that were lingering, which I thank you for.

    Quote Originally Posted by kyberfabrikken
    FrontController and ApplicationController are words which Martin Fowler have coined. He doesn't use the term dispatcher, but he does say that the "FrontController dispatches to a handler".
    Quote Originally Posted by kyberfabrikken
    A prime example is a controller for a form; If certain rules are met, the form is valid, and the control should be delegated to an onValid handler. If not, control should be delegated to an onInvalid handler. The part of your code, which does this is an ApplicationController.
    Quote Originally Posted by kyberfabrikken
    The ApplicationController may itself delegate to another ApplicationController, which means that there may be multiple ApplicationControllers for the same request. Eventually they will reach a controller, which doesn't delegate control further. This end-station will generate a response.

    Sorry to chomp your post into sections. I noticed somthing similar to this in the AP3 project, in one of the test applications. Whilst I do understand the real life situations for having this style of logic, and while I never throw away advice of knowledge, I feel that this type of EventHandling would be outside that of the project it's going to be applied to.

    What I was hoping to implement, without the ApplicationController holding that much EventDriven control was to have a "script" which was basically a class include of the CustomController (NewsClass.php) that would handle error checking $newsClass->isValidForm() etc, similar to that of the direction of the CodeIgniter project.

    That said, I see that only way of moving on with the learning code is to get a hard copy of notes planned out and a framework running.

    My long term goal, is to create it, and use projects such as Zend to steal ideas/methods from, but without the basic understanding of what was going on it would have been pointless.
    Keep life simple... don't put your head through plexiglass.

  8. #8
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ultimately, just to reinforce to any readers.. MVC isn't a guide of how to make your site step by step, it's your own interpretation of it to some degree.

    I will create a Dispatcher, as mentioned that once the View has finished, it'll get fed back too to create a ResponseHandler for outputting, atleast if theres any bugs then I'll know where to look.
    Keep life simple... don't put your head through plexiglass.

  9. #9
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Rather than trying to distinguish between frontcontroller, applicationcontroller and whatnot-controller, I think you will be better off recognizing that they are all special cases of controller. Figure out a minimum interface that describes all theese, and call this controller. You can then extend it and create specialized instances such as a frontcontroller or a formcontroller or action.

    Quote Originally Posted by DamienGiles
    Me too, it just didn't seem logical to have the View output directly to the browser, I suppose it could potentially make sense for the CustomController(news) to initial the ResponseHandler to output after Post-Filters have completed if thats what you mean... that's really the main reason for this thread.


    But then, thinking about it... If I wanted to change the way the Reponse Handler was called, I'd have to modify every CustomController, unless I have the CustomController extend a parent, that define the Outputting Stages, but this seems to break logic in my eyes.
    You could let all controllers return their response, and putting the output in the topmost controller (the dispatcher/frontontroller). This is really a intercepting-filter pattern, in that it allows each controller to modify the response before returning it.

  10. #10
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm sorry if I hijack your thread now, but I'm also trying to master MVC, and I'm having a hard time to understand how the filter chain should be implemented. Am I correct in that it should be the filters responsibility to check if a form has been filled out properly? And should I create new filters for every form, since the requirements for forms are almost always different. Or should I create one broad filter, and name my input boxes something like "email_required_text" and parse that in the filter?

  11. #11
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    wysiwyg,

    I won't "answer" your question as I'm not able to... however, my personal view of a filter is not to carry out checks on a page request... as kyberfabrikken indicates that this should be done within the ApplicationController and which I will do within the CustomController itself (with the aid of an external include class).

    In this forum, you'll see the filterChain being used for things like SessionManagement, Authorisation, GlobalVar Checking ($_POST, etc)... however, I'd simply be using a filter chain for something like this:


    PHP Code:
    $filterChain = new HTTPRequestHandler (); // Prepare all incomming vars safe 
    Not really a chain, but If I wanted to, extend it later... theres always the posibility...

    PHP Code:
    $filterChain = new HTTPRequestHandler (
      new 
    SessionHandler(
        new 
    Authorisation()
      )
    ); 
    Thanks
    Keep life simple... don't put your head through plexiglass.

  12. #12
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    Rather than trying to distinguish between frontcontroller, applicationcontroller and whatnot-controller, I think you will be better off recognizing that they are all special cases of controller. Figure out a minimum interface that describes all theese, and call this controller. You can then extend it and create specialized instances such as a frontcontroller or a formcontroller or action.


    You could let all controllers return their response, and putting the output in the topmost controller (the dispatcher/frontontroller). This is really a intercepting-filter pattern, in that it allows each controller to modify the response before returning it.
    kyberfabrikken, sounds like the route I was going down. I hope the list of points #'s helped anyone reading to try and visualize roughly what the scheme of things are.

    Thanks for the feedback.
    Keep life simple... don't put your head through plexiglass.

  13. #13
    SitePoint Zealot Serberus's Avatar
    Join Date
    Oct 2005
    Location
    Herts, UK
    Posts
    113
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think having a filter perform form validation might make it more than a filter. I presumed you'd have a seperate validation helper or some such object to aid the app controller (eg. NewsController) perform the validation?

    I think it's one thing to get your head around the flow of interaction between these patterns and then another to code them.

    I'm having a hard time to understand how the filter chain should be implemented
    This is just one way to implement a Filter Chain (or Intercepting Filter) in a FrontController:

    PHP Code:
    class FrontController {

        protected 
    $filterChain = array();
        
        public function 
    registerFilter($filter) {
        
            if (!
    class_exists($filter,false))
                require(
    'classes/'.$filter.'.inc');
            
            
    $this->filterChain[] = new $filter;
        
        }
        
        public function 
    run() {
        
            try {
                foreach (
    $this->getPreFilters() as $filter)
                    
    $this->filterChain[$filter]->preFilter();
            } catch (
    Exception $e) {
                
    // Dispatch to error handler
            
    }
                
            
    $this->process();
            
            try {
                foreach (
    $this->getPostFilters() as $filter)
                    
    $this->filterChain[$filter]->postFilter();
            } catch (
    Exception $e) {
                
    // Dispatch to error handler
            
    }
        
        }
        
        protected function 
    process() {
        
            
    // Fire up Request Handler, ActionMapper, Dispatcher and pass off to appropriate controller ??
            
        
    }
        
        private function 
    getPreFilters() {
        
            return 
    array_keys($this->filterChain);
        
        }
        
        private function 
    getPostFilters() {
        
            return 
    array_reverse($this->getPreFilters());
        
        }


    Your bootstrap file might look like this:

    PHP Code:
    <?php
    require('classes/FrontController.inc');

    $site = new FrontController();
    $site->registerFilter('HtmlCompressor');
    $site->registerFilter('SomethingElse');
    $site->run();

    ?>

  14. #14
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Serberus
    I think having a filter perform form validation might make it more than a filter. I presumed you'd have a seperate validation helper or some such object to aid the app controller (eg. NewsController) perform the validation?
    Serberus, not quite sure who that was aimed at, but looking at the AP3 project, theres a Validation.php, which includes a Rule Class, where Rules extend that Class such is EmailRule extends Rule.

    So in the Custom Controller (NewsController), it initiates the EmailRule, or whatever complex Rule to aid in validation without rewriting the same code (isThisARealEmailOrNot() function) in every seperate CustomController.

    ^^ That's pretty much identical to how I'm using a extended validation class.


    Quote Originally Posted by Serberus
    PHP Code:
    class FrontController {

        protected 
    $filterChain = array();
        
        public function 
    registerFilter($filter) {
        
            if (!
    class_exists($filter,false))
                require(
    'classes/'.$filter.'.inc');
            
            
    $this->filterChain[] = new $filter;
        
        }
        
        public function 
    run() {
        
            try {
                foreach (
    $this->getPreFilters() as $filter)
                    
    $this->filterChain[$filter]->preFilter();
            } catch (
    Exception $e) {
                
    // Dispatch to error handler
            
    }
                
            
    $this->process();
            
            try {
                foreach (
    $this->getPostFilters() as $filter)
                    
    $this->filterChain[$filter]->postFilter();
            } catch (
    Exception $e) {
                
    // Dispatch to error handler
            
    }
        
        }
        
        protected function 
    process() {
        
            
    // Fire up Request Handler, ActionMapper, Dispatcher and pass off to appropriate controller ??
            
        
    }
        
        private function 
    getPreFilters() {
        
            return 
    array_keys($this->filterChain);
        
        }
        
        private function 
    getPostFilters() {
        
            return 
    array_reverse($this->getPreFilters());
        
        }


    Your bootstrap file might look like this:

    PHP Code:
    <?php
    require('classes/FrontController.inc');

    $site = new FrontController();
    $site->registerFilter('HtmlCompressor');
    $site->registerFilter('SomethingElse');
    $site->run();

    ?>
    I like the example, I didn't have the time to draw my entire filterChain that your example details the Chain I believe.
    Keep life simple... don't put your head through plexiglass.

  15. #15
    SitePoint Zealot Serberus's Avatar
    Join Date
    Oct 2005
    Location
    Herts, UK
    Posts
    113
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My filter statement was to wysiwyg but you managed to squeeze in 2 posts before I got mine finished

    I'll have to have a gander at this AP3 project.

  16. #16
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wysiwyg
    I'm sorry if I hijack your thread now, but I'm also trying to master MVC, and I'm having a hard time to understand how the filter chain should be implemented. Am I correct in that it should be the filters responsibility to check if a form has been filled out properly? And should I create new filters for every form, since the requirements for forms are almost always different. Or should I create one broad filter, and name my input boxes something like "email_required_text" and parse that in the filter?
    InterceptingFilter is possibly the worst named pattern ever. It has nothing to do with filtering. An InterceptingFilter is a form of chain.
    Filtering of input like you do with a form is something you would do in the ApplicationController - not the FrontController.
    A form will need both filtering of data and validation of it. Thoose are two separate concerns. Inputfiltering is probably not something you would implement with an InterceptingFilter, that would be overkill - a straight chain will do fine for that.

  17. #17
    SitePoint Zealot Serberus's Avatar
    Join Date
    Oct 2005
    Location
    Herts, UK
    Posts
    113
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If these are not filters in the FrontController chain, is it safe to put authentication in this chain? Since it is something that needs to be checked on every request.

    The thing that makes me uncomfortable with doing this is the objects in my FC chain have pre & post processing methods. For an authentication object, I can only see the pre-processing one being of any use.

  18. #18
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    > or an authentication object, I can only see the pre-processing one being of any use.

    I would use the pre processing to preform the action required, and then use the post processing to log the performed action.

    You find that you need to do some form of logging anyways, so using the post processing to do the logging, the logging is tucked up, out of the way for you

  19. #19
    SitePoint Zealot Serberus's Avatar
    Join Date
    Oct 2005
    Location
    Herts, UK
    Posts
    113
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Good thunkin.

    However, working off my code in #13, if I add an Auth object to that chain and add logging features in the postFilter() method, would this only log Auth related information such as failed login attempts?

    Trying to handle logging for other parts of the web app at this point would muddy this objects role?

  20. #20
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes; Your logging in relation to the post process only relates to that specific action in question; But then again this is all you want anyways... Application specific logging requires you to take another course of action - another route in other words.

    From a framework point of view, your application wouldn't even know about the pre or post processing anyways, or at least your application shouldn't know about them anyways

  21. #21
    SitePoint Enthusiast DamienGiles's Avatar
    Join Date
    Mar 2005
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    wysiwyg, does that answer your filterChain question?
    Keep life simple... don't put your head through plexiglass.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •