<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def publish(spec, nb_name, template='full', save_first=True):
 """ Converts nb_name to an HTML file. Preserves widget functionality. Outputs a link to download HTML file after conversion if called in a notebook environment. Equivalent to running `nbinteract ${spec} ${nb_name}` on the command line. Args: spec (str):
 BinderHub spec for Jupyter image. Must be in the format: `${username}/${repo}/${branch}`. nb_name (str):
 Complete name of the notebook file to convert. Can be a relative path (eg. './foo/test.ipynb'). Kwargs: template (str):
 Template to use for conversion. Valid templates: - 'full': Outputs a complete standalone HTML page with default styling. Automatically loads the nbinteract JS library. - 'partial': Outputs an HTML partial that can be embedded in another page. Automatically loads the nbinteract JS library but has no styling. - 'plain': Outputs an HTML partial used to embed in an HTML page where the nbinteract JS library is already loaded. Does not load JS library or styling save_first (bool):
 If True, saves the currently opened notebook before converting nb_name. Used to ensure notebook is written to filesystem before starting conversion. Does nothing if not in a notebook environment. Returns: None """

    if not os.path.isfile(nb_name):
        raise ValueError(
            "{} isn't a path to a file. Double check your "
            "filename and try again.".format(nb_name)
        )

    if save_first:
        _save_nb(nb_name)

    print('Converting notebook...')
    try:
        check_output(
            ['nbinteract', '--template', template, '--spec', spec, nb_name],
            stderr=STDOUT
        )
    except CalledProcessError as err:
        logging.warning(
            ERROR_MESSAGE.format(
                filename=nb_name, error=str(err.output, 'utf-8')
            )
        )
        return

    html_filename = os.path.splitext(nb_name)[0] + '.html'
    display(Markdown(CONVERT_SUCCESS_MD.format(url=html_filename)))