def install_bower(self, package, save=True, save_dev=False):
        """Installs a bower package.

        :param save: if `True`, pins the package to the Hydrogen requirements
            YAML file.
        :param save_dev: if `True`, pins the package as a development
            dependency to the Hydrogen requirements YAML file.
        :param return: a list of tuples, containing all installed package names
            and versions, including any dependencies.
        """
        requirement = Requirement.coerce(package)
        url = Bower.get_package_url(requirement.package)

        installed = []
        for name, _ in self.get_bower_package(url):
            installed.append(Requirement(name, requirement.version))

        for requirement in installed:
            if save:
                self.requirements["bower"].add(requirement, replace=True)
            if save_dev:
                self.requirements["bower-dev"].add(requirement, replace=True)
            success("installed {}".format(str(requirement)))
        if save or save_dev:
            self.requirements.save()
        return installed
def find_sounding_files(
        top_sounding_dir_name, radar_file_name_matrix, target_names,
        lag_time_for_convective_contamination_sec):
    """Locates files with storm-centered soundings.

    D = number of SPC dates in time period

    :param top_sounding_dir_name: Name of top-level directory.  Files therein
        will be found by `soundings.find_sounding_file`.
    :param radar_file_name_matrix: numpy array created by either
        `find_storm_images_2d` or `find_storm_images_3d`.  Length of the first
        axis is D.
    :param target_names: See doc for `_check_target_vars`.
    :param lag_time_for_convective_contamination_sec: See doc for
        `soundings.read_soundings`.
    :return: sounding_file_names: length-D list of file paths.
    """

    error_checking.assert_is_numpy_array(radar_file_name_matrix)
    num_file_dimensions = len(radar_file_name_matrix.shape)
    error_checking.assert_is_geq(num_file_dimensions, 2)
    error_checking.assert_is_leq(num_file_dimensions, 3)

    mean_lead_time_seconds = _check_target_vars(target_names)[0]

    num_file_times = radar_file_name_matrix.shape[0]
    sounding_file_names = [''] * num_file_times

    for i in range(num_file_times):
        if num_file_dimensions == 2:
            this_file_name = radar_file_name_matrix[i, 0]
        else:
            this_file_name = radar_file_name_matrix[i, 0, 0]

        this_time_unix_sec, this_spc_date_string = (
            storm_images.image_file_name_to_time(this_file_name)
        )

        sounding_file_names[i] = soundings.find_sounding_file(
            top_directory_name=top_sounding_dir_name,
            spc_date_string=this_spc_date_string,
            lead_time_seconds=mean_lead_time_seconds,
            lag_time_for_convective_contamination_sec=
            lag_time_for_convective_contamination_sec,
            init_time_unix_sec=this_time_unix_sec, raise_error_if_missing=True)

    return sounding_file_names