<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _parse_url(url, fully_qualified=False):
 """Parse the given charm or bundle URL, provided as a string. Return a tuple containing the entity reference fragments: schema, user, series, name and revision. Each fragment is a string except revision (int). Raise a ValueError with a descriptive message if the given URL is not valid. If fully_qualified is True, the URL must include the schema, series and revision, otherwise a ValueError is raised. """

    # Retrieve the schema.
    try:
        schema, remaining = url.split(':', 1)
    except ValueError:
        if fully_qualified:
            msg = 'URL has no schema: {}'.format(url)
            raise ValueError(msg.encode('utf-8'))
        schema = 'cs'
        remaining = url
    if schema not in ('cs', 'local'):
        msg = 'URL has invalid schema: {}'.format(schema)
        raise ValueError(msg.encode('utf-8'))
    # Retrieve and validate the optional user.
    parts = remaining.split('/')
    part = parts.pop(0)
    user = ''
    if part.startswith('~'):
        user = part[1:]
        if not valid_user(user):
            msg = 'URL has invalid user name: {}'.format(user)
            raise ValueError(msg.encode('utf-8'))
        if schema == 'local':
            msg = 'local entity URL with user name: {}'.format(url)
            raise ValueError(msg.encode('utf-8'))
        if not parts:
            msg = 'URL has invalid form: {}'.format(url)
            raise ValueError(msg.encode('utf-8'))
        part = parts.pop(0)
    # Retrieve and validate the series.
    series = ''
    if parts:
        series = part
        if not valid_series(series):
            msg = 'URL has invalid series: {}'.format(series)
            raise ValueError(msg.encode('utf-8'))
        part = parts.pop(0)
    elif fully_qualified:
        msg = 'URL has invalid form: {}'.format(url)
        raise ValueError(msg.encode('utf-8'))
    # Retrieve and validate name and revision.
    if parts:
        msg = 'URL has invalid form: {}'.format(url)
        raise ValueError(msg.encode('utf-8'))
    try:
        name, revision = part.rsplit('-', 1)
    except ValueError:
        if fully_qualified:
            msg = 'URL has no revision: {}'.format(url)
            raise ValueError(msg.encode('utf-8'))
        name, revision = part, None
    if revision is not None:
        try:
            revision = int(revision)
        except ValueError:
            if fully_qualified:
                msg = 'URL has invalid revision: {}'.format(revision)
                raise ValueError(msg.encode('utf-8'))
            name, revision = name + '-' + revision, None
    if not valid_name(name):
        msg = 'URL has invalid name: {}'.format(name)
        raise ValueError(msg.encode('utf-8'))
    return schema, user, series, name, revision