static fromTextDiagram(gateMap, diagram) {
        let lines = seq(diagram.split('\n')).map(e => e.trim()).filter(e => e !== '').toArray();
        if (seq(lines.map(e => e.length)).distinct().count() > 1) {
            throw new DetailedError("Uneven diagram", {diagram});
        }

        let rowCount = lines.length;
        let colCount = lines.length > 0 ? lines[0].length : 0;

        let spanAt = (col, row) => {
            for (let d = 1; row + d < lines.length; d++) {
                if (gateMap.get(lines[row + d][col]) !== null) {
                    return d;
                }
            }
            return lines.length - row;
        };

        return new CircuitDefinition(
            rowCount,
            Seq.range(colCount).
                map(col => new GateColumn(seq(lines).mapWithIndex((line, row) => {
                    let char = line[col];
                    if (!gateMap.has(char)) {
                        throw new DetailedError("Unspecified gate", {char});
                    }
                    let gateOrFamily = gateMap.get(char);
                    if (gateOrFamily === null || gateOrFamily === undefined) {
                        return undefined;
                    }
                    if (gateOrFamily.hasOwnProperty('ofSize')) {
                        return gateOrFamily.ofSize(spanAt(col, row));
                    }
                    if (gateOrFamily instanceof Gate) {
                        return gateOrFamily;
                    }

                    throw new DetailedError("Not a gate", gateOrFamily);
                }).toArray())).
                toArray());
    }
This mainly exists for writing tests that are understandable.
@param {!string} diagram
@param {!Map.<!string, !Gate|!{ofSize: !function(!int) : !Gate}>} gateMap
@returns {!CircuitDefinition}