Return a list of all valid urls (minus args and kwargs, just the program paths)
        for this manifest. If a single program has two urls, both will be returned.

def get_urls(self, controllers=None, prefix_path=''):
        """
        Return a list of all valid urls (minus args and kwargs, just the program paths)
        for this manifest. If a single program has two urls, both will be returned.
        """
        tag_match = lambda program: set(program.controllers) & set(controllers or [])
        urls = set()

        for key, value in self.manifest.items():

            path = "%s/%s" % (prefix_path, key)

            if path.endswith('/') and prefix_path:
                path = path[:-1]

            if hasattr(value, 'lower'):
                # is a string redirect
                urls.add(path)

            elif isinstance(value, Manifest):
                # is manifest
                pp = '' if path == '/' else path # for 'stacked' root programs.
                new_urls = value.get_urls(controllers=controllers, prefix_path=pp)
                urls.update(new_urls)

            elif isinstance(value, Program):
                # make a list so we can iterate through it in the next `if` block
                value = [value]

            if hasattr(value, 'append'):
                # defined is multiple programs, get the one for this controller tag.
                for program in value:
                    if not program.controllers or not controllers:
                        # no controllers defined on program. Always add.
                        # or no tags defined for this get_urls call. Always add.
                        urls.add(path)
                    elif tag_match(program):
                        urls.add(path)

        return urls