Initial data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 72d218235f
commit f23f22d71c
199087 changed files with 3378941 additions and 0 deletions

View file

@ -0,0 +1,83 @@
<!doctype html>
<html id="doc">
<head><meta charset="utf-8"/>
<title>Stuff</title>
<script type="application/javascript">
function gid(id) { return document.getElementById(id); }
function ce(tag, cls, parent_node) {
var e = document.createElement(tag);
e.className = cls;
if (parent_node) parent_node.appendChild(e);
return e;
}
function dom_tree(id) {
gid('tree').textContent = "";
gid('tree').appendChild(mktree(gid(id), null));
}
function mktree(e, p) {
var t = ce("div", "tree", p);
var tog = ce("span", "toggle", t);
var h = ce("span", "tag", t);
if (e.tagName === undefined) {
h.textContent = "#Text";
var txt = e.textContent;
if (txt.length > 0 && txt.match(/\S/)) {
h = ce("div", "txt", t);
h.textContent = txt;
}
return t;
}
tog.textContent = "";
tog.onclick = function () { clicked(tog); }
h.textContent = e.nodeName;
var l = e.childNodes;
for (var i = 0; i != l.length; i++)
mktree(l[i], t);
return t;
}
function clicked(e) {
var is_on = e.textContent == "";
e.textContent = is_on ? "+" : "";
e.parentNode.className = is_on ? "tree-hide" : "tree";
}
</script>
<style>
#tree { white-space: pre; font-family: monospace; border: 1px solid }
.tree > .tree-hide, .tree > .tree
{ margin-left: 2em; border-left: 1px dotted rgba(0,0,0,.2)}
.tree-hide > .tree, .tree-hide > .tree-hide { display: none }
.tag { color: navy }
.tree-hide > .tag { color: maroon }
.txt { color: gray; padding: 0 .5em; margin: 0 .5em 0 2em; border: 1px dotted rgba(0,0,0,.1) }
.toggle { display: inline-block; width: 2em; text-align: center }
</style>
</head>
<body>
<article>
<section>
<h1>Headline</h1>
Blah blah
</section>
<section>
<h1>More headline</h1>
<blockquote>Something something</blockquote>
<section><h2>Nested section</h2>
Somethin somethin list:
<ul>
<li>Apples</li>
<li>Oranges</li>
<li>Cetera Fruits</li>
</ul>
</section>
</section>
</article>
<div id="tree"><a href="javascript:dom_tree('doc')">click me</a></div>
</body>
</html>

View file

@ -0,0 +1,300 @@
(() => {
'use strict';
// UTF8 character-drawn tree, with options for compacting vs
// centering parents, and for pruning out nodeless lines.
const example = `
Epsilon
Beta Zeta
Eta
Alpha Gamma Theta
Iota
Delta Kappa
Lambda`
// drawTree2 :: Bool -> Bool -> Tree String -> String
const drawTree2 = blnCompact => blnPruned => tree => {
// Tree design and algorithm inspired by the Haskell snippet at:
// https://doisinkidney.com/snippets/drawing-trees.html
const
// Lefts, Middle, Rights
lmrFromStrings = xs => {
const [ls, rs] = Array.from(splitAt(
Math.floor(xs.length / 2),
xs
));
return Tuple3(ls, rs[0], rs.slice(1));
},
stringsFromLMR = lmr =>
Array.from(lmr).reduce((a, x) => a.concat(x), []),
fghOverLMR = (f, g, h) => lmr => {
const [ls, m, rs] = Array.from(lmr);
return Tuple3(ls.map(f), g(m), rs.map(h));
};
const lmrBuild = (f, w) => wsTree => {
const
leftPad = n => s => ' '.repeat(n) + s,
xs = wsTree.nest,
lng = xs.length,
[nChars, x] = Array.from(wsTree.root);
// LEAF NODE --------------------------------------
return 0 === lng ? (
Tuple3([], '─'.repeat(w - nChars) + x, [])
// NODE WITH SINGLE CHILD -------------------------
) : 1 === lng ? (() => {
const indented = leftPad(1 + w);
return fghOverLMR(
indented,
z => '─'.repeat(w - nChars) + x + '─' + z,
indented
)(f(xs[0]));
// NODE WITH CHILDREN -----------------------------
})() : (() => {
const
cFix = x => xs => x + xs,
treeFix = (l, m, r) => compose(
stringsFromLMR,
fghOverLMR(cFix(l), cFix(m), cFix(r))
),
_x = '─'.repeat(w - nChars) + x,
indented = leftPad(w),
lmrs = xs.map(f);
return fghOverLMR(
indented,
s => _x + ({
'┌': '┬',
'├': '┼',
'│': '┤',
'└': '┴'
})[s[0]] + s.slice(1),
indented
)(lmrFromStrings(
intercalate(
blnCompact ? [] : ['│'],
[treeFix(' ', '┌', '│')(lmrs[0])]
.concat(init(lmrs.slice(1)).map(
treeFix('│', '├', '│')
))
.concat([treeFix('│', '└', ' ')(
lmrs[lmrs.length - 1]
)])
)
));
})();
};
const
measuredTree = fmapTree(
v => {
const s = ' ' + v + ' ';
return Tuple(s.length, s)
}, tree
),
levelWidths = init(levels(measuredTree))
.reduce(
(a, level) => a.concat(maximum(level.map(fst))),
[]
),
treeLines = stringsFromLMR(
levelWidths.reduceRight(
lmrBuild, x => x
)(measuredTree)
);
return unlines(
blnPruned ? (
treeLines.filter(
s => s.split('')
.some(c => !' │'.includes(c))
)
) : treeLines
);
};
// TESTS ----------------------------------------------
const main = () => {
// tree :: Tree String
const tree = Node(
'Alpha', [
Node('Beta', [
Node('Epsilon', []),
Node('Zeta', []),
Node('Eta', [])
]),
Node('Gamma', [Node('Theta', [])]),
Node('Delta', [
Node('Iota', []),
Node('Kappa', []),
Node('Lambda', [])
])
]);
// tree2 :: Tree Int
const tree2 = Node(
1,
[
Node(2, [
Node(4, []),
Node(5, [Node(7, [])])
]),
Node(3, [
Node(6, [
Node(8, []),
Node(9, [])
])
])
]
);
// strTrees :: String
const strTrees = ([
'Compacted (parents not all vertically centered):',
drawTree2(true)(false)(tree2),
'Fully expanded, with vertical centering:',
drawTree2(false)(false)(tree),
'Vertically centered, with nodeless lines pruned out:',
drawTree2(false)(true)(tree),
].join('\n\n'));
return (
console.log(strTrees),
strTrees
);
};
// GENERIC FUNCTIONS ----------------------------------
// Node :: a -> [Tree a] -> Tree a
const Node = (v, xs) => ({
type: 'Node',
root: v, // any type of value (consistent across tree)
nest: xs || []
});
// Tuple (,) :: a -> b -> (a, b)
const Tuple = (a, b) => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
// Tuple3 (,,) :: a -> b -> c -> (a, b, c)
const Tuple3 = (a, b, c) => ({
type: 'Tuple3',
'0': a,
'1': b,
'2': c,
length: 3
});
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (f, g) => x => f(g(x));
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (() => {
const unit = 'string' !== typeof xs[0] ? (
[]
) : '';
return unit.concat.apply(unit, xs);
})() : [];
// fmapTree :: (a -> b) -> Tree a -> Tree b
const fmapTree = (f, tree) => {
const go = node => Node(
f(node.root),
node.nest.map(go)
);
return go(tree);
};
// fst :: (a, b) -> a
const fst = tpl => tpl[0];
// identity :: a -> a
const identity = x => x;
// init :: [a] -> [a]
const init = xs =>
0 < xs.length ? (
xs.slice(0, -1)
) : undefined;
// intercalate :: [a] -> [[a]] -> [a]
// intercalate :: String -> [String] -> String
const intercalate = (sep, xs) =>
0 < xs.length && 'string' === typeof sep &&
'string' === typeof xs[0] ? (
xs.join(sep)
) : concat(intersperse(sep, xs));
// intersperse(0, [1,2,3]) -> [1, 0, 2, 0, 3]
// intersperse :: a -> [a] -> [a]
// intersperse :: Char -> String -> String
const intersperse = (sep, xs) => {
const bln = 'string' === typeof xs;
return xs.length > 1 ? (
(bln ? concat : x => x)(
(bln ? (
xs.split('')
) : xs)
.slice(1)
.reduce((a, x) => a.concat([sep, x]), [xs[0]])
)) : xs;
};
// iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a]
const iterateUntil = (p, f, x) => {
const vs = [x];
let h = x;
while (!p(h))(h = f(h), vs.push(h));
return vs;
};
// Returns Infinity over objects without finite length.
// This enables zip and zipWith to choose the shorter
// argument when one is non-finite, like cycle, repeat etc
// length :: [a] -> Int
const length = xs =>
(Array.isArray(xs) || 'string' === typeof xs) ? (
xs.length
) : Infinity;
// levels :: Tree a -> [[a]]
const levels = tree =>
iterateUntil(
xs => 1 > xs.length,
ys => [].concat(...ys.map(nest)),
[tree]
).map(xs => xs.map(root));
// maximum :: Ord a => [a] -> a
const maximum = xs =>
0 < xs.length ? (
xs.slice(1).reduce((a, x) => x > a ? x : a, xs[0])
) : undefined;
// nest :: Tree a -> [a]
const nest = tree => tree.nest;
// root :: Tree a -> a
const root = tree => tree.root;
// splitAt :: Int -> [a] -> ([a], [a])
const splitAt = (n, xs) =>
Tuple(xs.slice(0, n), xs.slice(n));
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// MAIN ---
return main();
})();

View file

@ -0,0 +1,130 @@
(() => {
'use strict';
// drawTree :: Bool -> Tree String -> String
const drawTree = blnCompact => tree => {
// Simple decorated-outline style of ascii tree drawing,
// with nodeless lines pruned out if blnCompact is True.
const xs = draw(tree);
return unlines(
blnCompact ? (
xs.filter(
s => s.split('')
.some(c => !' │'.includes(c))
)
) : xs
);
};
// draw :: Tree String -> [String]
const draw = node => {
// shift :: String -> String -> [String] -> [String]
const shift = (first, other, xs) =>
zipWith(
append,
cons(first, replicate(xs.length - 1, other)),
xs
);
// drawSubTrees :: [Tree String] -> [String]
const drawSubTrees = xs => {
const lng = xs.length;
return 0 < lng ? (
1 < lng ? append(
cons(
'│',
shift('├─ ', '│ ', draw(xs[0]))
),
drawSubTrees(xs.slice(1))
) : cons('│', shift('└─ ', ' ', draw(xs[0])))
) : [];
};
return append(
lines(node.root.toString()),
drawSubTrees(node.nest)
);
};
// TEST -----------------------------------------------
const main = () => {
const tree = Node(
'Alpha', [
Node('Beta', [
Node('Epsilon', []),
Node('Zeta', []),
Node('Eta', [])
]),
Node('Gamma', [Node('Theta', [])]),
Node('Delta', [
Node('Iota', []),
Node('Kappa', []),
Node('Lambda', [])
])
]);
return [true, false]
.map(blnCompact => drawTree(blnCompact)(tree))
.join('\n\n');
};
// GENERIC FUNCTIONS ----------------------------------
// Node :: a -> [Tree a] -> Tree a
const Node = (v, xs) => ({
type: 'Node',
root: v, // any type of value (consistent across tree)
nest: xs || []
});
// append (++) :: [a] -> [a] -> [a]
// append (++) :: String -> String -> String
const append = (xs, ys) => xs.concat(ys);
// chars :: String -> [Char]
const chars = s => s.split('');
// cons :: a -> [a] -> [a]
const cons = (x, xs) => [x].concat(xs);
// Returns Infinity over objects without finite length.
// This enables zip and zipWith to choose the shorter
// argument when one is non-finite, like cycle, repeat etc
// length :: [a] -> Int
const length = xs =>
(Array.isArray(xs) || 'string' === typeof xs) ? (
xs.length
) : Infinity;
// lines :: String -> [String]
const lines = s => s.split(/[\r\n]/);
// replicate :: Int -> a -> [a]
const replicate = (n, x) =>
Array.from({
length: n
}, () => x);
// take :: Int -> [a] -> [a]
const take = (n, xs) =>
xs.slice(0, n);
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// Use of `take` and `length` here allows zipping with non-finite lists
// i.e. generators like cycle, repeat, iterate.
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) => {
const
lng = Math.min(length(xs), length(ys)),
as = take(lng, xs),
bs = take(lng, ys);
return Array.from({
length: lng
}, (_, i) => f(as[i], bs[i], i));
};
// MAIN ---
return main();
})();