<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def controller(url_prefix_or_controller_cls: Union[str, Type[Controller]], controller_cls: Optional[Type[Controller]] = None, *, rules: Optional[Iterable[Union[Route, RouteGenerator]]] = None, ) -> RouteGenerator: """ This function is used to register a controller class's routes. Example usage:: routes = lambda: [ controller(SiteController), ] Or with the optional prefix argument:: routes = lambda: [ controller('/products', ProductController), ] Specify ``rules`` to only include those routes from the controller:: routes = lambda: [ controller(SecurityController, rules=[ rule('/login', SecurityController.login), rule('/logout', SecurityController.logout), rule('/sign-up', SecurityController.register), ]), ] :param url_prefix_or_controller_cls: The controller class, or a url prefix for all of the rules from the controller class passed as the second argument :param controller_cls: If a url prefix was given as the first argument, then the controller class must be passed as the second argument :param rules: An optional list of rules to limit/customize the routes included from the controller """

    url_prefix, controller_cls = _normalize_args(
        url_prefix_or_controller_cls, controller_cls, _is_controller_cls)
    url_prefix = url_prefix or controller_cls.Meta.url_prefix

    routes = []
    controller_routes = getattr(controller_cls, CONTROLLER_ROUTES_ATTR)
    if rules is None:
        routes = controller_routes.values()
    else:
        for route in _reduce_routes(rules):
            existing = controller_routes.get(route.method_name)
            if existing:
                routes.append(_inherit_route_options(route, existing[0]))
            else:
                routes.append(route)

    yield from _normalize_controller_routes(routes, controller_cls,
                                            url_prefix=url_prefix)