def extend_resources(self, version, attr_map):
        processed_exts = {}
        exts_to_process = self.extensions.copy()
        check_optionals = True
        # Iterate until there are unprocessed extensions or if no progress
        # is made in a whole iteration
        while exts_to_process:
            processed_ext_count = len(processed_exts)
            for ext_name, ext in list(exts_to_process.items()):
                # Process extension only if all required extensions
                # have been processed already
                required_exts_set = set(ext.get_required_extensions())
                if required_exts_set - set(processed_exts):
                    continue
                optional_exts_set = set(ext.get_optional_extensions())
                if check_optionals and optional_exts_set - set(processed_exts):
                    continue
                extended_attrs = ext.get_extended_resources(version)
                for res, resource_attrs in six.iteritems(extended_attrs):
                    attr_map.setdefault(res, {}).update(resource_attrs)
                processed_exts[ext_name] = ext
                del exts_to_process[ext_name]
            if len(processed_exts) == processed_ext_count:
                # if we hit here, it means there are unsatisfied
                # dependencies. try again without optionals since optionals
                # are only necessary to set order if they are present.
                if check_optionals:
                    check_optionals = False
                    continue
                # Exit loop as no progress was made
                break
        if exts_to_process:
            unloadable_extensions = set(exts_to_process.keys())
            LOG.error(_LE("Unable to process extensions (%s) because "
                          "the configured plugins do not satisfy "
                          "their requirements. Some features will not "
                          "work as expected."),
                      ', '.join(unloadable_extensions))
            # Fail gracefully for default extensions, just in case some out
            # of tree plugins are not entirely up to speed
            default_extensions = set(const.DEFAULT_SERVICE_PLUGINS.values())
            if not unloadable_extensions <= default_extensions:
                raise exceptions.ExtensionsNotFound(
                    extensions=list(unloadable_extensions))

        # Extending extensions' attributes map.
        for ext in processed_exts.values():
            ext.update_attributes_map(attr_map)
.. todo::
dataset/ETHPy150Open openstack/neutron/neutron/api/extensions.py/ExtensionManager.extend_resources--crossover with--dataset/ETHPy150Open lisa-lab/pylearn2/pylearn2/sandbox/cuda_convnet/probabilistic_max_pooling.py/prob_max_pool_c01b