def _normalize(self):
        """Convert the project to a standardised form for the current plugin.

        Called after loading, before saving, and when converting to a new
        format.

        Yields UnsupportedFeature instances.

        """

        unique_sprite_names = set(sprite.name for sprite in self.sprites)
        if len(unique_sprite_names) < len(self.sprites):
            raise ValueError, "Sprite names must be unique"

        # sync self.sprites and self.actors
        for sprite in self.sprites:
            if sprite not in self.actors:
                self.actors.append(sprite)
        for actor in self.actors:
            if isinstance(actor, Sprite):
                if actor not in self.sprites:
                    raise ValueError, \
                        "Can't have sprite on stage that isn't in sprites"

        # normalize Scriptables
        self.stage._normalize()
        for sprite in self.sprites:
            sprite._normalize()

        # normalize actors
        for actor in self.actors:
            if not isinstance(actor, Scriptable):
                actor._normalize()

        # make Watchers if needed
        for thing in [self, self.stage] + self.sprites:
            for (name, var) in thing.variables.items():
                if not var.watcher:
                    var.watcher = kurt.Watcher(thing,
                            kurt.Block("var", name), is_visible=False)
                    self.actors.append(var.watcher)
            for (name, list_) in thing.lists.items():
                if not list_.watcher:
                    list_.watcher = kurt.Watcher(thing,
                            kurt.Block("list", name), is_visible=False)
                    self.actors.append(list_.watcher)

        # notes - line endings
        self.notes = self.notes.replace("\r\n", "\n").replace("\r", "\n")

        # convert scripts
        def convert_block(block):
            # convert block
            try:
                if isinstance(block.type, CustomBlockType):
                    if "Custom Blocks" not in self._plugin.features:
                        raise BlockNotSupported(
                                "%s doesn't support custom blocks"
                                % self._plugin.display_name)

                else: # BlockType
                    pbt = block.type.convert(self._plugin)
            except BlockNotSupported, err:
                err.message += ". Caused by: %r" % block
                err.block = block
                err.scriptable = scriptable
                err.args = (err.message,)
                if getattr(block.type, '_workaround', None):
                    block = block.type._workaround(block)
                    if not block:
                        raise
                else:
                    raise

            # convert args
            args = []
            for arg in block.args:
                if isinstance(arg, Block):
                    arg = convert_block(arg)
                elif isinstance(arg, list):
                    arg = map(convert_block, arg)
                args.append(arg)
            block.args = args

            return block

        for scriptable in [self.stage] + self.sprites:
            for script in scriptable.scripts:
                if isinstance(script, Script):
                    script.blocks = map(convert_block, script.blocks)

        # workaround unsupported features
        for feature in kurt.plugin.Feature.FEATURES.values():
            if feature not in self._plugin.features:
                for x in feature.workaround(self):
                    yield UnsupportedFeature(feature, x)

        # normalize supported features
        for feature in self._plugin.features:
            feature.normalize(self)