11cb0ef41Sopenharmony_cimodule.exports = function (rows_, opts) {
21cb0ef41Sopenharmony_ci    if (!opts) opts = {};
31cb0ef41Sopenharmony_ci    var hsep = opts.hsep === undefined ? '  ' : opts.hsep;
41cb0ef41Sopenharmony_ci    var align = opts.align || [];
51cb0ef41Sopenharmony_ci    var stringLength = opts.stringLength
61cb0ef41Sopenharmony_ci        || function (s) { return String(s).length; }
71cb0ef41Sopenharmony_ci    ;
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci    var dotsizes = reduce(rows_, function (acc, row) {
101cb0ef41Sopenharmony_ci        forEach(row, function (c, ix) {
111cb0ef41Sopenharmony_ci            var n = dotindex(c);
121cb0ef41Sopenharmony_ci            if (!acc[ix] || n > acc[ix]) acc[ix] = n;
131cb0ef41Sopenharmony_ci        });
141cb0ef41Sopenharmony_ci        return acc;
151cb0ef41Sopenharmony_ci    }, []);
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci    var rows = map(rows_, function (row) {
181cb0ef41Sopenharmony_ci        return map(row, function (c_, ix) {
191cb0ef41Sopenharmony_ci            var c = String(c_);
201cb0ef41Sopenharmony_ci            if (align[ix] === '.') {
211cb0ef41Sopenharmony_ci                var index = dotindex(c);
221cb0ef41Sopenharmony_ci                var size = dotsizes[ix] + (/\./.test(c) ? 1 : 2)
231cb0ef41Sopenharmony_ci                    - (stringLength(c) - index)
241cb0ef41Sopenharmony_ci                ;
251cb0ef41Sopenharmony_ci                return c + Array(size).join(' ');
261cb0ef41Sopenharmony_ci            }
271cb0ef41Sopenharmony_ci            else return c;
281cb0ef41Sopenharmony_ci        });
291cb0ef41Sopenharmony_ci    });
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci    var sizes = reduce(rows, function (acc, row) {
321cb0ef41Sopenharmony_ci        forEach(row, function (c, ix) {
331cb0ef41Sopenharmony_ci            var n = stringLength(c);
341cb0ef41Sopenharmony_ci            if (!acc[ix] || n > acc[ix]) acc[ix] = n;
351cb0ef41Sopenharmony_ci        });
361cb0ef41Sopenharmony_ci        return acc;
371cb0ef41Sopenharmony_ci    }, []);
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci    return map(rows, function (row) {
401cb0ef41Sopenharmony_ci        return map(row, function (c, ix) {
411cb0ef41Sopenharmony_ci            var n = (sizes[ix] - stringLength(c)) || 0;
421cb0ef41Sopenharmony_ci            var s = Array(Math.max(n + 1, 1)).join(' ');
431cb0ef41Sopenharmony_ci            if (align[ix] === 'r' || align[ix] === '.') {
441cb0ef41Sopenharmony_ci                return s + c;
451cb0ef41Sopenharmony_ci            }
461cb0ef41Sopenharmony_ci            if (align[ix] === 'c') {
471cb0ef41Sopenharmony_ci                return Array(Math.ceil(n / 2 + 1)).join(' ')
481cb0ef41Sopenharmony_ci                    + c + Array(Math.floor(n / 2 + 1)).join(' ')
491cb0ef41Sopenharmony_ci                ;
501cb0ef41Sopenharmony_ci            }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci            return c + s;
531cb0ef41Sopenharmony_ci        }).join(hsep).replace(/\s+$/, '');
541cb0ef41Sopenharmony_ci    }).join('\n');
551cb0ef41Sopenharmony_ci};
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_cifunction dotindex (c) {
581cb0ef41Sopenharmony_ci    var m = /\.[^.]*$/.exec(c);
591cb0ef41Sopenharmony_ci    return m ? m.index + 1 : c.length;
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_cifunction reduce (xs, f, init) {
631cb0ef41Sopenharmony_ci    if (xs.reduce) return xs.reduce(f, init);
641cb0ef41Sopenharmony_ci    var i = 0;
651cb0ef41Sopenharmony_ci    var acc = arguments.length >= 3 ? init : xs[i++];
661cb0ef41Sopenharmony_ci    for (; i < xs.length; i++) {
671cb0ef41Sopenharmony_ci        f(acc, xs[i], i);
681cb0ef41Sopenharmony_ci    }
691cb0ef41Sopenharmony_ci    return acc;
701cb0ef41Sopenharmony_ci}
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_cifunction forEach (xs, f) {
731cb0ef41Sopenharmony_ci    if (xs.forEach) return xs.forEach(f);
741cb0ef41Sopenharmony_ci    for (var i = 0; i < xs.length; i++) {
751cb0ef41Sopenharmony_ci        f.call(xs, xs[i], i);
761cb0ef41Sopenharmony_ci    }
771cb0ef41Sopenharmony_ci}
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_cifunction map (xs, f) {
801cb0ef41Sopenharmony_ci    if (xs.map) return xs.map(f);
811cb0ef41Sopenharmony_ci    var res = [];
821cb0ef41Sopenharmony_ci    for (var i = 0; i < xs.length; i++) {
831cb0ef41Sopenharmony_ci        res.push(f.call(xs, xs[i], i));
841cb0ef41Sopenharmony_ci    }
851cb0ef41Sopenharmony_ci    return res;
861cb0ef41Sopenharmony_ci}
87