a method to start a local container

        :param image_name: string with name or id of image
        :param container_alias: string with name to assign to container
        :param image_tag: [optional] string with tag assigned to image
        :param environmental_variables: [optional] dictionary of envvar fields to add to container
        :param mapped_ports: [optional] dictionary of port fields to map to container
        :param mounted_volumes: [optional] dictionary of path fields to map to container
        :param start_command: [optional] string of command (and any arguments) to run inside container
        :param network_name: [optional] string with name of docker network to link container to 
        :param run_flags: [optional] string with additional docker options to add to container
        :return: string with container id

        NOTE:   valid characters for environmental variables key names follow the shell
                standard of upper and lower alphanumerics or underscore and cannot start
                with a numerical value.

        NOTE:   ports are mapped such that the key name is the system port and the
                value is the port inside the container. both must be strings of digits.
        
        NOTE:   volumes are mapped such that the key name is the absolute or relative
                system path and the value is the absolute path inside the container. 
                both must be strings.
        
        NOTE:   additional docker options:
                    --entrypoint    overrides existing entrypoint command
                    --rm            removes container once start command exits
                    --log-driver    sets system logging settings for the container
                https://docs.docker.com/engine/reference/run

def run(self, image_name, container_alias, image_tag='', environmental_variables=None, mapped_ports=None, mounted_volumes=None, start_command='', network_name='', run_flags=''):

        '''
             a method to start a local container

        :param image_name: string with name or id of image
        :param container_alias: string with name to assign to container
        :param image_tag: [optional] string with tag assigned to image
        :param environmental_variables: [optional] dictionary of envvar fields to add to container
        :param mapped_ports: [optional] dictionary of port fields to map to container
        :param mounted_volumes: [optional] dictionary of path fields to map to container
        :param start_command: [optional] string of command (and any arguments) to run inside container
        :param network_name: [optional] string with name of docker network to link container to 
        :param run_flags: [optional] string with additional docker options to add to container
        :return: string with container id

        NOTE:   valid characters for environmental variables key names follow the shell
                standard of upper and lower alphanumerics or underscore and cannot start
                with a numerical value.

        NOTE:   ports are mapped such that the key name is the system port and the
                value is the port inside the container. both must be strings of digits.
        
        NOTE:   volumes are mapped such that the key name is the absolute or relative
                system path and the value is the absolute path inside the container. 
                both must be strings.
        
        NOTE:   additional docker options:
                    --entrypoint    overrides existing entrypoint command
                    --rm            removes container once start command exits
                    --log-driver    sets system logging settings for the container
                https://docs.docker.com/engine/reference/run
        '''
    
        title = '%s.run' % self.__class__.__name__

    # validate inputs
        input_fields = {
            'image_name': image_name,
            'container_alias': container_alias,
            'image_tag': image_tag,
            'environmental_variables': environmental_variables,
            'mapped_ports': mapped_ports,
            'mounted_volumes': mounted_volumes,
            'start_command': start_command,
            'network_name': network_name,
            'run_flags': run_flags
        }
        for key, value in input_fields.items():
            if value:
                object_title = '%s(%s=%s)' % (title, key, str(value))
                self.fields.validate(value, '.%s' % key, object_title)

    # validate subfields
        if environmental_variables:
            for key, value in environmental_variables.items():
                key_title = '%s(environmental_variables={%s:...})' % (title, key)
                self.fields.validate(key, '.envvar_key', key_title)
                value_title = '%s(environmental_variables={%s:%s})' % (title, key, str(value))
                self.fields.validate(value, '.envvar_value', value_title)
        else:
            environmental_variables = {}
        if mapped_ports:
            for key, value in mapped_ports.items():
                key_title = '%s(mapped_ports={%s:...})' % (title, key)
                self.fields.validate(key, '.port_key', key_title)
                value_title = '%s(mapped_ports={%s:%s})' % (title, key, str(value))
                self.fields.validate(value, '.port_value', value_title)
        else:
            mapped_ports = {}
        if mounted_volumes:
            for key, value in mounted_volumes.items():
                key_title = '%s(mounted_volumes={%s:...})' % (title, key)
                self.fields.validate(key, '.mount_field', key_title)
                value_title = '%s(mounted_volumes={%s:%s})' % (title, key, str(value))
                self.fields.validate(value, '.mount_field', value_title)
        else:
            mounted_volumes = {}
    
    # TODO verify image exists (locally or remotely) ???

    # verify alias does not exist
        for container in self.ps():
            if container['NAMES'] == container_alias:
                raise ValueError('%s(container_alias="%s") already exists. Try first: docker rm -f %s' % (title, container_alias, container_alias))

    # verify network exists
        network_exists = False
        for network in self.network_ls():
            if network['NAME'] == network_name:
                network_exists = True
        if network_name and not network_exists:
            raise ValueError('%s(network_name="%s") does not exist. Try first: docker network create %s' % (title, network_name, network_name))

    # verify system paths and compose absolute path mount map
        absolute_mounts = {}
        from os import path
        for key, value in mounted_volumes.items():
            if not path.exists(key):
                raise ValueError('%s(mounted_volume={%s:...}) is not a valid path on localhost.' % (title, key))
            absolute_path = path.abspath(key)
            if self.localhost.os.sysname == 'Windows':
                absolute_path = '"/%s"' % absolute_path
            else:
                absolute_path = '"%s"' % absolute_path
            absolute_mounts[absolute_path] = '"%s"' % value

    # compose run command
        sys_cmd = 'docker run --name %s' % container_alias
        for key, value in environmental_variables.items():
            sys_cmd += ' -e %s=%s' % (key.upper(), value)
        for key, value in mapped_ports.items():
            sys_cmd += ' -p %s:%s' % (key, value)
        for key, value in absolute_mounts.items():
            sys_cmd += ' -v %s:%s' % (key, value)
        if network_name:
            sys_cmd += ' --network %s' % network_name
        if run_flags:
            sys_cmd += ' %s' % run_flags.strip()
        sys_cmd += ' -d %s' % image_name
        if image_tag:
            sys_cmd += ':%s' % image_tag
        if start_command:
            sys_cmd += ' %s' % start_command.strip()

    # run run command
        output_lines = self.command(sys_cmd).split('\n')

        return output_lines[0]