def add_handler(app, config):
    """Add a single handler to the app.

    Adds one IIIF Image API handler to app, with config from config.

    Arguments:
        app - Flask app
        config - Configuration object in which:
            config.prefix - String path prefix for this handler
            config.client_prefix - String path prefix seen by client (which may be different
                because of reverse proxy or such
            config.klass_name - Manipulator class, e.g. 'pil'
            config.api_version - e.g. '2.1'
            config.include_osd - True or False to include OSD
            config.gauth_client_secret_file - filename if auth_type='gauth'
            config.access_cookie_lifetime - number of seconds
            config.access_token_lifetime - number of seconds
            config.auth_type - Auth type string or 'none'

    Returns True on success, nothing otherwise.
    """
    auth = None
    if (config.auth_type is None or config.auth_type == 'none'):
        pass
    elif (config.auth_type == 'gauth'):
        from iiif.auth_google import IIIFAuthGoogle
        auth = IIIFAuthGoogle(client_secret_file=config.gauth_client_secret_file)
    elif (config.auth_type == 'basic'):
        from iiif.auth_basic import IIIFAuthBasic
        auth = IIIFAuthBasic()
    elif (config.auth_type == 'clickthrough'):
        from iiif.auth_clickthrough import IIIFAuthClickthrough
        auth = IIIFAuthClickthrough()
    elif (config.auth_type == 'kiosk'):
        from iiif.auth_kiosk import IIIFAuthKiosk
        auth = IIIFAuthKiosk()
    elif (config.auth_type == 'external'):
        from iiif.auth_external import IIIFAuthExternal
        auth = IIIFAuthExternal()
    else:
        logging.error("Unknown auth type %s, ignoring" % (config.auth_type))
        return
    if (auth is not None):
        auth.access_cookie_lifetime = config.access_cookie_lifetime
        auth.access_token_lifetime = config.access_token_lifetime
    klass = None
    if (config.klass_name == 'pil'):
        from iiif.manipulator_pil import IIIFManipulatorPIL
        klass = IIIFManipulatorPIL
    elif (config.klass_name == 'netpbm'):
        from iiif.manipulator_netpbm import IIIFManipulatorNetpbm
        klass = IIIFManipulatorNetpbm
    elif (config.klass_name == 'dummy'):
        from iiif.manipulator import IIIFManipulator
        klass = IIIFManipulator
    elif (config.klass_name == 'gen'):
        from iiif.manipulator_gen import IIIFManipulatorGen
        klass = IIIFManipulatorGen
    else:
        logging.error("Unknown manipulator type %s, ignoring" % (config.klass_name))
        return
    base = urljoin('/', config.prefix + '/')  # ensure has trailing slash
    client_base = urljoin('/', config.client_prefix + '/')  # ensure has trailing slash
    logging.warning("Installing %s IIIFManipulator at %s v%s %s" %
                    (config.klass_name, base, config.api_version, config.auth_type))
    params = dict(config=config, klass=klass, auth=auth, prefix=config.client_prefix)
    app.add_url_rule(base.rstrip('/'), 'prefix_index_page',
                     prefix_index_page, defaults={'config': config})
    app.add_url_rule(base, 'prefix_index_page',
                     prefix_index_page, defaults={'config': config})
    app.add_url_rule(base + '<string(minlength=1):identifier>/info.json',
                     'options_handler', options_handler, methods=['OPTIONS'])
    app.add_url_rule(base + '<string(minlength=1):identifier>/info.json',
                     'iiif_info_handler', iiif_info_handler, methods=['GET'], defaults=params)
    if (config.include_osd):
        app.add_url_rule(base + '<string(minlength=1):identifier>/osd.html',
                         'osd_page_handler', osd_page_handler, methods=['GET'], defaults=params)
    app.add_url_rule(base + '<string(minlength=1):identifier>/<path:path>',
                     'iiif_image_handler', iiif_image_handler, methods=['GET'], defaults=params)
    if (auth):
        setup_auth_paths(app, auth, config.client_prefix, params)
    # redirects to info.json must come after auth
    app.add_url_rule(base + '<string(minlength=1):identifier>',
                     'iiif_info_handler',
                     redirect_to=client_base + '<identifier>/info.json')
    app.add_url_rule(base + '<string(minlength=1):identifier>/',
                     'iiif_info_handler',
                     redirect_to=client_base + '<identifier>/info.json')
    return True
Add a single handler to the app.

    Adds one IIIF Image API handler to app, with config from config.

    Arguments:
        app - Flask app
        config - Configuration object in which:
            config.prefix - String path prefix for this handler
            config.client_prefix - String path prefix seen by client (which may be different
                because of reverse proxy or such
            config.klass_name - Manipulator class, e.g. 'pil'
            config.api_version - e.g. '2.1'
            config.include_osd - True or False to include OSD
            config.gauth_client_secret_file - filename if auth_type='gauth'
            config.access_cookie_lifetime - number of seconds
            config.access_token_lifetime - number of seconds
            config.auth_type - Auth type string or 'none'

    Returns True on success, nothing otherwise.