'Find descendant nodes of a node
@param node_id: the node ID (can be an iterable of node IDs)
@param category: find nodes of this category
@param classify: return each node as tuple (id, category) instead
of just ids
@param inclusive: include the start node(s) if they match
@return: a set of node IDs (or tuples (id, category), respectively)'

def findall(self, node_id, category=DEFAULT, classify=False, inclusive=False):

    result = set()
    findall = self.findall
    if isinstance(node_id, (set, list, tuple)):
        for n in node_id:
            if (n is None):
                continue
            result |= findall(n, category=category, classify=classify, inclusive=inclusive)
        return result
    nodes = self.nodes
    node = nodes.get(node_id)
    if (not node):
        return result
    if node['s']:
        result |= findall(node['s'], category=category, classify=classify, inclusive=True)
    if inclusive:
        this = ((node_id, node['c']) if classify else node_id)
        if ((category is DEFAULT) or (category == node['c'])):
            result.add(this)
    return result
