<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def add(self, name, interface, inputs=None, outputs=None, requirements=None, wall_time=None, annotations=None, **kwargs):
 """ Adds a processing Node to the pipeline Parameters name : str Name for the node interface : nipype.Interface The interface to use for the node inputs : dict[str, (str, FileFormat) | (Node, str)] Connections from inputs of the pipeline and outputs of other nodes to inputs of node. The keys of the dictionary are the field names and the values are 2-tuple containing either the name of the data spec and the data format it is expected in for pipeline inputs or the sending Node and the the name of an output of the sending Node. Note that pipeline inputs can be specified outside this method using the 'connect_input' method and connections between nodes with the the 'connect' method. outputs : dict[str, (str, FileFormat)] Connections to outputs of the pipeline from fields of the interface. The keys of the dictionary are the names of the data specs that will be written to and the values are the interface field name and the data format it is produced in. Note that output connections can also be specified using the 'connect_output' method. requirements : list(Requirement) List of required packages need for the node to run (default: []) wall_time : float Time required to execute the node in minutes (default: 1) mem_gb : int Required memory for the node in GB n_procs : int Preferred number of threads to run the node on (default: 1) annotations : dict[str, *] Additional annotations to add to the node, which may be used by the Processor node to optimise execution (e.g. 'gpu': True) iterfield : str Name of field to be passed an iterable to iterator over. If present, a MapNode will be created instead of a regular node joinsource : str Name of iterator field to join. Typically one of the implicit iterators (i.e. Study.SUBJECT_ID or Study.VISIT_ID) to join over the subjects and/or visits joinfield : str Name of field to pass the joined list when creating a JoinNode Returns ------- node : Node The Node object that has been added to the pipeline """

        if annotations is None:
            annotations = {}
        if requirements is None:
            requirements = []
        if wall_time is None:
            wall_time = self.study.processor.default_wall_time
        if 'mem_gb' not in kwargs or kwargs['mem_gb'] is None:
            kwargs['mem_gb'] = self.study.processor.default_mem_gb
        if 'iterfield' in kwargs:
            if 'joinfield' in kwargs or 'joinsource' in kwargs:
                raise ArcanaDesignError(
                    "Cannot provide both joinsource and iterfield to when "
                    "attempting to add '{}' node to {}"
                    .foramt(name, self._error_msg_loc))
            node_cls = self.study.environment.node_types['map']
        elif 'joinsource' in kwargs or 'joinfield' in kwargs:
            if not ('joinfield' in kwargs and 'joinsource' in kwargs):
                raise ArcanaDesignError(
                    "Both joinsource and joinfield kwargs are required to "
                    "create a JoinNode (see {})".format(name,
                                                        self._error_msg_loc))
            joinsource = kwargs['joinsource']
            if joinsource in self.study.ITERFIELDS:
                self._iterator_joins.add(joinsource)
            node_cls = self.study.environment.node_types['join']
            # Prepend name of pipeline of joinsource to match name of nodes
            kwargs['joinsource'] = '{}_{}'.format(self.name, joinsource)
        else:
            node_cls = self.study.environment.node_types['base']
        # Create node
        node = node_cls(self.study.environment,
                        interface,
                        name="{}_{}".format(self._name, name),
                        requirements=requirements,
                        wall_time=wall_time,
                        annotations=annotations,
                        **kwargs)
        # Ensure node is added to workflow
        self._workflow.add_nodes([node])
        # Connect inputs, outputs and internal connections
        if inputs is not None:
            assert isinstance(inputs, dict)
            for node_input, connect_from in inputs.items():
                if isinstance(connect_from[0], basestring):
                    input_spec, input_format = connect_from
                    self.connect_input(input_spec, node,
                                       node_input, input_format)
                else:
                    conn_node, conn_field = connect_from
                    self.connect(conn_node, conn_field, node, node_input)
        if outputs is not None:
            assert isinstance(outputs, dict)
            for output_spec, (node_output, output_format) in outputs.items():
                self.connect_output(output_spec, node, node_output,
                                    output_format)
        return node