noxz-sites

A collection of a builder and various scripts creating the noxz.tech sites
git clone https://noxz.tech/git/noxz-sites.git
Log | Files | README | LICENSE

build
1#!/bin/sh
2
3# ---------------------------- global variables ----------------------------- #
4SITE_DOMAIN="noxz.tech"
5SITE_TITLE="noxz.tech | "
6SITE_MAIN_TITLE="noxz.tech"
7SITE_AUTHOR="Chris Noxz"
8SITE_ICON_PNG="//[site]/pub/logo.png"
9SITE_ICON_SVG="//[site]/pub/logo.svg"
10SITE_CSS="//[site]/pub/style.css"
11SITE_GIT_REPO_ROOT="${HOME}/mnt/src/z0noxz"
12SITE_GIT_COMMIT_PH="repo-logs"
13SITE_GIT_COMMIT_COUNT="100"
14SITE_WWW=
15SITE_HTML=
16SITE_REPLACE_DOT=1
17# ------------------------------ config files ------------------------------- #
18CFG_DIR="./config"
19# ------------------------ groff configuration files ------------------------ #
20CFG_GROFF_WWW_MACRO="${CFG_DIR}/www.conf"
21CFG_GROFF_EQN="${CFG_DIR}/eqn.conf"
22# ---------------------- main html configuration files ---------------------- #
23CFG_MAIN_HTML="${CFG_DIR}/main.html"
24# ---------------------- git html configuration files ----------------------- #
25CFG_GIT_REPOS_HTML="${CFG_DIR}/git_repos.html"
26CFG_GIT_HEAD_HTML="${CFG_DIR}/git_head.html"
27# --------------------- sitemap.xml configuration files --------------------- #
28CFG_SITEMAP_XML="${CFG_DIR}/sitemap.xml"
29CFG_SITEMAP_XML_ITEM="${CFG_DIR}/sitemap_item.xml"
30# ------------------------ pinned tag configuration  ------------------------ #
31CFG_PINNED_TAG="pinned"
32
33
34# helper function to fix dot files if asked to do so
35# shellcheck disable=SC2120
36fix_dot_file() {
37	if [ ${SITE_REPLACE_DOT} -ne 1 ]; then
38		if [ ! -t 0 ]; then
39			cat -
40		elif [ -n "${1}" ]; then
41			echo "${1}"
42		fi
43	else
44		if [ ! -t 0 ]; then
45			cat -
46		elif [ -n "${1}" ]; then
47			echo "${1}"
48		fi                                                                  \
49		| sed                                                               \
50			-e "s,/\.,/_\.,g"                                               \
51			-e "s,^\.,_\.,g"
52	fi
53}
54
55# helper function to html encode stdin
56# shellcheck disable=SC2120
57html_encode() {
58	if [ ! -t 0 ]; then
59		cat -
60	elif [ -n "$1" ]; then
61		echo "$1"
62	fi                                                                      \
63	| sed                                                                   \
64		-e 's/&/\&/g'                                                   \
65		-e 's/"/\"/g'                                                  \
66		-e 's/</\&lt;/g'                                                    \
67		-e 's/>/\&gt;/g'
68}
69
70# helper function to produce awk safe strings
71# shellcheck disable=SC2120
72awk_safe() {
73	if [ ! -t 0 ]; then
74		cat -
75	elif [ -n "$1" ]; then
76		echo "$1"
77	fi                                                                      \
78	|  sed                                                                  \
79		-e 's/\\/\\\\/g'                                                    \
80		-e 's/\&/\\\\\&/g'
81}
82
83print_loading() {
84	>&2 printf '[%s*%s] %-.100s '                                           \
85		"$(tput setaf 4)"                                                   \
86		"$(tput sgr 0)"                                                     \
87		"${1} $(for _ in $(seq 1 100); do printf '.'; done)"
88}
89
90print_done() {
91	>&2 printf '[%sdone%s]\n'                                               \
92		"$(tput setaf 2)"                                                   \
93		"$(tput sgr 0)"
94}
95
96# arg 1: site root eg. ../noxz-sites/noxz.tech
97# arg 2: current site eg. ../noxz-sites/noxz.tech/guides/groff
98render_main_menu() {
99	# variables used in main menu
100	menu_root="${1}"
101	menu_current="${2}"
102	menu_active=""
103	menu_output=""
104	menu_buffer=""
105	menu_home="$(printf '<li><a href="//%s/">home</a></li>' "${SITE_DOMAIN}")"
106
107	# check if both directories exist
108	[ ! -d "${menu_root}" ] && return
109	[ ! -d "${menu_current}" ] && return
110
111	# remove trailing slashes if existing
112	menu_root=$(dirname "${menu_root}/*")
113	menu_current=$(dirname "${menu_current}/*")
114
115	# make sure current directory is a subdirectory of root
116	echo "${menu_current}" | grep -qv "^${menu_root}" && return
117
118	# root menu
119	if [ "${menu_root}" = "${menu_current}" ]; then
120		menu_home="$(echo "${menu_home}" | sed 's/<li/<li class="active"/')"
121		for f in "${menu_current}"/*; do
122			[ ! -d "${f}" ] && continue                                     # only process directories
123			[ -f "${f}/.buildignore" ] && continue                          # skip buildignore
124
125			ff="$(echo "${f}" | sed "s?^${menu_root}?//${SITE_DOMAIN}?")"
126			fn="$(echo "${f##*/}" | sed 's/_/ /g')"
127			menu_output=$(printf '%s<li><a href="%s">%s</a></li>'           \
128				"${menu_output}"                                            \
129				"${ff}"                                                     \
130				"${fn}")
131		done
132	fi
133
134	# run until root directory is the current one
135	while [ "${menu_root}" != "${menu_current}" ]; do
136
137		# handle children of first current
138		if [ "${menu_current}" = "${2}" ]; then
139			for f in "${menu_current}"/*; do
140				[ ! -d "${f}" ] && continue                                 # only process directories
141				[ -f "${f}/.buildignore" ] && continue                      # skip buildignore
142				menu_output="$(printf '%s<li' "${menu_output}")"
143				ff="$(echo "${f}" | sed "s?^${menu_root}?//${SITE_DOMAIN}?")"
144				fn="$(echo "${f##*/}" | sed 's/_/ /g')"
145				menu_output=$(printf '%s><a href="%s">%s</a></li>'          \
146					"${menu_output}"                                        \
147					"${ff}"                                                 \
148					"${fn}")
149			done
150		fi
151
152		menu_active="${menu_current}"                                       # mark current as active
153		menu_current="${menu_current%/*}"                                   # mark parent as current
154
155		# handle all siblings
156		for f in "${menu_current}"/*; do
157			[ ! -d "${f}" ] && continue                                     # only process directories
158			[ -f "${f}/.buildignore" ] && continue                          # skip buildignore
159
160			menu_buffer=$(printf '%s<li' "${menu_buffer}")
161			ff="$(echo "${f}" | sed "s?^${menu_root}?//${SITE_DOMAIN}?")"
162			fn="$(echo "${f##*/}" | sed 's/_/ /g')"
163			if [ "${f}" = "${menu_active}" ]; then                          # treat active different
164				menu_buffer=$(printf '%s class="active"><a href="%s">%s</a>'\
165					"${menu_buffer}"                                        \
166					"${ff}"                                                 \
167					"${fn}")
168				# dump output to buffer if existing (sub menu)
169				[ "${menu_output}" != "" ]                                  \
170				&& menu_buffer=$(printf '%s<ul>%s</ul>'                     \
171					"${menu_buffer}"                                        \
172					"${menu_output}")
173				menu_buffer=$(printf '%s</li>' "${menu_buffer}")
174			else
175				menu_buffer=$(printf '%s><a href="%s">%s</a></li>'          \
176					"${menu_buffer}"                                        \
177					"${ff}"                                                 \
178					"${fn}")
179			fi
180		done
181		menu_output="${menu_buffer}"
182		menu_buffer=""
183	done
184	printf '<ul id="main-nav">%s%s</ul>'                                    \
185		"${menu_home}"                                                      \
186		"${menu_output}"                                                    \
187	| sed                                                                   \
188		-e 's,\(<\(ul\|li\)[^>]*>\|</ul>\),\n\1,2g'                         \
189		-e 's,\(</ul>\)\(</li>\),\1\n\2,g'                                  \
190	| awk '
191		BEGIN {
192			level=0
193		}
194
195		/<\/ul>/ {
196			level--
197		}
198
199		/^<\/li>$/ {
200			level--
201		}
202
203		{
204			for (i=0; i<level; i++)
205				printf "\t"
206			print
207		}
208
209		/<ul[^>]*>/ {
210			level++
211		}
212
213		/<li[^>]*>.*<\/a>$/ {
214			level++
215		}
216	'
217}
218
219render_main_menu_extra() {
220	printf '<li><a class="%s" href="%s">%s</a></li>\n'                      \
221		"pin"    "//[site]/articles/tags/pinned" "pinned articles"          \
222		"howto"  "//[site]/articles/tags/howto"  "how to"                   \
223		"twtxt"  "//[site]/twtxt.txt" "twtxt"                               \
224		"source" "//[site]/git/" "source"                                   \
225	| awk                                                                   \
226	'
227		BEGIN {
228			printf "<ul id=\"extra-nav\">\n"
229		}
230
231		{
232			printf "\t%s\n", $0
233		}
234
235		END {
236			printf "</ul>\n"
237		}
238	'
239}
240
241render_articles() {
242	# copy tag list from tags page
243	[ -z "${2}" ] && sed -e 's,\.ARTTAG "\([^"]*\)",.ARTTAG "tags/\1",g'    \
244		"${1}"/articles/tags/index.www
245	echo .DIVS articles
246	[ -n "${2}" ] && printf '.ULS\n'
247	if [ "${2}" != "${CFG_PINNED_TAG}" ]; then
248		find "${1}"/articles -name .metadata | while read -r article
249		do
250			grep "^.ds YEAR" "${article}" | sed 's/^.ds YEAR[^0-9]*//g'
251		done | sort -ru
252	else
253		# merge every year for pinned articles, to sort them alphabetically
254		echo
255	fi | while read -r year
256	do
257		[ -z "${2}" ] && printf '.HnS 1\n%s\n.HnE\n\.ULS\n' "${year}"
258		if [ -z "${2}" ]; then
259			grep -l "^.ds YEAR.*${year}" "${1}"/articles/*/.metadata
260		else # filter by tag
261			grep -l "^${2}$" "${1}"/articles/*/.tags                        \
262				| sed 's/\.tags$/.metadata/g'                               \
263				| xargs -I{} grep -l "^.ds YEAR.*${year}" "{}"
264		fi | xargs -I{} awk -v name="{}" -v tag="${2}" -v cfg_pinned_tag="${CFG_PINNED_TAG}" '
265			BEGIN {
266				title = ""
267				year = ""
268				month = ""
269				day = ""
270				gsub(/\/.metadata/,"",name)
271				gsub(/^([^\/]|\/)*\//,"",name)
272				printf ".LI\\n "
273			}
274			/^\.ds TITLE.*$/ {
275				for(i=3;i<=NF;i++) {
276					title = title$i
277					if (i != NF)
278						title = title" "
279				}
280			}
281			/^\.ds YEAR.*$/ {
282				year = $3
283			}
284			/^\.ds MONTH.*$/ {
285				month = substr($3,1,3)
286			}
287			/^\.ds DAY.*$/ {
288				day = $3
289			}
290			END {
291				if (tag == cfg_pinned_tag)
292					printf ".URL \"../../%s\" \"%s\"\n", name, title
293				else if (tag != "")
294					printf "%s %s, %s \\(em\\n .URL \"../../%s\" \"%s\"\n", day, month, year, name, title
295				else
296					printf "%s %s \\(em\\n .URL \"%s\" \"%s\"\n", day, month, name, title
297			}
298		' "{}" | if [ "${2}" = "${CFG_PINNED_TAG}" ]; then
299			sort -k 4
300		else
301			sort -k 3Mr -k 2nr
302		fi | sed -e 's/\\n /\n/g'
303		[ -z "${2}" ] && printf '.ULE\n'
304	done
305	[ -n "${2}" ] && printf '.ULE\n'
306	echo .DIVE
307}
308
309# fix for grohtml not reliably working for picture extraction
310extract_pictures() {
311	base_path="${SITE_WWW%/*}"
312	eqn=""
313	in_eqn=0
314	i=0
315
316	cat - | while read -r line; do
317		if [ $in_eqn -eq 0 ] && [ "$(echo ${line} | grep '^\.EQ')" = ".EQ" ]; then
318			in_eqn=1
319			eqn=""
320		fi
321		# catch and save every EQN instance
322		if [ $in_eqn -eq 1 ]; then
323			eqn="${eqn}${line}\n"
324		else
325			printf '%s\n' "${line}"
326		fi
327		# render and save EQN instance as a png image
328		if [ $in_eqn -eq 1 ] && [ "$(echo ${line} | grep '^\.EN')" = ".EN" ]; then
329			in_eqn=0
330			echo "${eqn}"                                                   \
331			| cat "${CFG_GROFF_EQN}" -                                      \
332			| groff -e -k -Tpdf                                             \
333			| convert -density 150 pdf:- -trim -quality 100 -sharpen 0x1.0 -resize 70% png:- > "${base_path}"/"eqn-${i}.png"
334			printf '.IMG %s/eqn-%s.png\n'                                   \
335				"${base_path}"                                              \
336				"${i}"
337			i=$((i+1))
338		fi
339	done
340}
341
342prerender() {
343	base_path="${SITE_WWW%/*}"
344	title=""
345	author=""
346	date=""
347
348	[ -f "${base_path}"/.metadata ] && while read -r line; do
349		case "$line" in
350		\.ds\ TITLE*)   title="$(echo ${line#*TITLE})";;
351		\.ds\ DATE*)    date="$(echo ${line#*DATE})";;
352		\.ds\ AUTHOR*)  author="$(echo ${line#*AUTHOR})";;
353		esac
354		printf '%s\n' "${line}"
355	done < "${base_path}"/.metadata
356
357	[ -n "$title" ] && printf '\n.ll 10i\n\n.HnS 0\n\\*[TITLE]\n.HnE\n\n'
358	[ -n "$author" ] && printf '.P article-author\n\\*[AUTHOR]\n\n'
359	[ -n "$date" ] && printf '.P article-date\n\\*[DATE]\n\n'
360
361	# print tags, if existing, at bottom of page
362	[ -f "${base_path}"/.tags ]                                             \
363		&& printf '\n.DIVS wrap-list\n.ULS\n'                               \
364		&& while read -r tag; do
365		if [ "${tag}" != "${CFG_PINNED_TAG}" ]; then
366			tag_safe="$(echo "${tag}" | tr \  _)"
367			printf '.LI\n.CLURL "../tags/%s" art-tag "%s"\n' "${tag_safe}" "${tag}"
368		fi
369	done < "${base_path}"/.tags && printf '.ULE\n.DIVE\n\n'
370
371	[ -f "${base_path}"/.edit ] \
372		&& sed "${base_path}"/.edit                                         \
373		-e 's/^START \([0-9-]*\)$/.LI \1\n.ULS/g'                           \
374		-e 's/^\t\(.*\)$/.LI\n\1/g'                                         \
375		-e 's/^END$/.ULE/g'                                                 \
376		-e '1 i\.DIVS edit-note\n.HnS 2\nEdit notice\n.HnE\n.DLS'           \
377		-e '$ a .DLE\n.DIVE\n'
378
379	cat - | while read -r line; do
380		if echo "${line}" | grep -E '\{:articles(#[^#]*)?:\}' 2>/dev/null 1>&2; then
381			render_articles "$1"                                            \
382				"$(echo "${line}" | sed 's/\([^#]*#\?\)\(.*\)\(:.*$\)/\2/')"
383		else
384			printf '%s\n' "${line}"
385		fi
386	done
387}
388
389render_main_content() {
390	awk '
391		# Grohtml (post-html.cpp) has a hard coded max length:
392		# https://git.savannah.gnu.org/cgit/groff.git/tree/src/devices/grohtml/post-html.cpp
393		# 51: #define MAX_LINE_LENGTH                   60
394		# This creates a problem when printing words longer than 60 characters -
395		# creating an extra blank line before the word. Further more grohtml
396		# actually do not print code blocks using <code> or <pre> so blank lines
397		# that are supposed to be printed are instead ignored. These following
398		# awk scripts together with some extensions of the www-macros (see.
399		# www.conf) are supposed to fix these issues.
400
401		BEGIN { # initialize variables
402			_inblock=0
403		}
404
405		/\.COS/ {
406			_inblock=1
407		}
408
409		/\.COE/ {
410			_inblock=0
411		}
412
413		{ # normal: no fixes applied
414			if (!_inblock) {
415				print
416				next
417			}
418		}
419
420		## INSIDE CODE BLOCK ##
421
422		# replace blank lines with extended BR macro
423		/^$/ {
424			print ".COMMENT-BR"
425			next
426		}
427
428		/\t/ { # replace tabs with 4 spaces
429			gsub(/\t/, "    ", $0);
430		}
431
432		{ # very ugly fix to preserve spaces (see if this can be imporoved upon)
433			# NOTE: angle brackets will be encoded by groff!
434			gsub(/\s{2}/, "<!--space--><!--space-->", $0)
435			gsub(/<!--space-->\s/, "<!--space--><!--space-->", $0)
436			print
437		}
438	' "${SITE_WWW}"                                                         \
439	| extract_pictures  "$1"                                                \
440	| prerender "$1"                                                        \
441	| cat "${CFG_GROFF_WWW_MACRO}" -                                        \
442	| groff                                                                 \
443		-Thtml -e -mwww -k                                                  \
444		-I"${SITE_WWW%/*}/grohtml-"                                         \
445	| awk '
446		# --------------------------------------------
447		# somewhat messy fix for code block formatting
448		# --------------------------------------------
449		BEGIN { # initialize variables
450			_inblock=0
451			_break=0
452		}
453
454		/<pre><code>/ { # signal start of code block
455			_inblock=1
456		}
457
458		/<\/code><\/pre>/ { # signal end of code block
459			_inblock=0
460		}
461
462		{ # normal: no fixes applied
463			if (!_inblock) {
464				print
465				next
466			}
467		}
468
469		## INSIDE CODE BLOCK ##
470
471		/^$/ { # fix: skip blank lines in code blocks
472			next
473		}
474
475		{ # handle general code block instances
476			# replace placeholders
477			gsub(/&lt;!--space--&gt;/, " ", $0);    # groff has now encoded angle brackets
478			gsub(/<!--break-->/, "", $0);
479
480			if (!_break)
481				printf " "
482			_break=0
483		}
484
485		/<br[^>]*>/ { # signal line break
486			_break=1
487		}
488
489		{
490			gsub(/<br[^>]*>/, "\n", $0);
491			printf "%s", $0
492		}
493	'                                                                       \
494	| sed                                                                   \
495		-e 's/<p style[^>]*>/<p>/g'                                         \
496		-e 's/<dd>/<dd><p>/g'                                               \
497		-e 's/<p><!--/<!--/g' -e 's/--><\/p>/-->/g'                         \
498		-e 's/\[at\]/<span>\&#64;<\/span>/g'                                \
499		-e 's/\(src\|alt\)="[^"]*\(eqn-[0-9]*.png\)/\1="\2/g'               \
500		-e 's/\(<img src="eqn-[0-9]*.png" alt="eqn-[0-9]*.png"\)[^>]*>/<p class="eqn">\1\/><\/p>/g' \
501		-e 's/<p align="\(left\|center\|right\)"[^>]*>/<p class="\1">/g'    \
502		-e 's/<pre><code>/<div class="code-wrap"><pre><code>/g'             \
503		-e 's/<\/code><\/pre>/<\/code><\/pre><\/div>/g'                     \
504	| tidy -asxhtml                                                         \
505	| sed -e '/^\s*<dd><\/dd>$/d'                                           \
506	| awk '
507		/<body>/{
508			flag=1
509			next
510		}
511
512		/<\/body>/{
513			flag=0
514		}
515
516		flag
517	'                                                                       \
518	| awk '
519		BEGIN { # initialize variables
520			_inblock=0
521		}
522
523		{ # normal: no fixes applied
524			if (NR > 1 && !_inblock) {
525				printf "<!--padding-->"
526			}
527			print
528		}
529		/<pre><code>/ { # signal start of code block
530			_inblock=1
531		}
532
533		/<\/code><\/pre>/ { # signal end of code block
534			_inblock=0
535		}
536	'
537}
538
539render_main() {
540	main_current="${2}"
541
542	[ ! -d "${main_current}" ] && return
543	main_current=$(dirname "${main_current}/*")
544
545	[ -f "${main_current}/index.www" ] && SITE_WWW="${main_current}/index.www" || return
546	[ -f "${main_current}/.metadata" ] && SITE_TITLE="${SITE_TITLE}$(grep '\.ds TITLE' "${main_current}/.metadata" | sed 's/\.ds\ TITLE\s*/.ll 10i\n/g' | groff -Tutf8 | sed -n '1,1p')"
547	SITE_HTML="${SITE_WWW%.*}.html"
548
549	print_loading "Rendering ${main_current}"
550
551	awk                                                                     \
552		-v var_author="$(awk_safe "${SITE_AUTHOR}")"                        \
553		-v var_title="$(awk_safe "${SITE_TITLE}")"                          \
554		-v var_favicon="$(awk_safe "${SITE_ICON_PNG}")"                     \
555		-v var_stylesheet="$(awk_safe "${SITE_CSS}")"                       \
556		-v var_logo="$(awk_safe "${SITE_ICON_SVG}")"                        \
557		-v var_main_title="$(awk_safe "${SITE_MAIN_TITLE}")"                \
558		-v var_menu="$(render_main_menu "$1" "$2" | awk_safe)"              \
559		-v var_menu_extra="$(render_main_menu_extra | awk_safe)"            \
560		-v var_content="$(render_main_content "$1" 2>/dev/null | awk_safe)" \
561		-v var_year="$(date +%Y)"                                           \
562	'
563		/\{:menu:\}/{
564			padding=$0
565			gsub(/{:.*:}$/, "", padding)
566			gsub(/\n/, "\n" padding, var_menu)
567		}
568
569		/\{:menu_extra:\}/{
570			padding=$0
571			gsub(/{:.*:}$/, "", padding)
572			gsub(/\n/, "\n" padding, var_menu_extra)
573		}
574
575		/\{:content:\}/{
576			padding=$0
577			gsub(/{:.*:}$/, "", padding)
578			gsub(/<!--padding-->/, padding, var_content)
579		}
580
581		{
582			gsub(/\{:author:\}/, var_author)
583			gsub(/\{:title:\}/, var_title)
584			gsub(/\{:favicon:\}/, var_favicon)
585			gsub(/\{:stylesheet:\}/, var_stylesheet)
586			gsub(/\{:logo:\}/, var_logo)
587			gsub(/\{:main_title:\}/, var_main_title)
588			gsub(/\{:sub_title:\}/, var_sub_title)
589			gsub(/\{:menu:\}/, var_menu)
590			gsub(/\{:menu_extra:\}/, var_menu_extra)
591			gsub(/\{:content:\}/, var_content)
592			gsub(/\{:year:\}/, var_year)
593			print
594		}
595	' "${CFG_MAIN_HTML}" > "${SITE_HTML}"
596
597	print_done
598}
599
600render_git_commit() {
601	git_commit_files="$(git -C "${1}" whatchanged "${2}"^! | grep '^:.*$' | cut -d' ' -f5 | sed 's/\t/:/g')"
602	git -C "${1}" show --stat=1000 --stat-graph-width=20 "${2}"             \
603		--format="format:%H%n%P%n%aN%n%aE%n%aD%n%B%H"                       \
604		| sed 's/{\(.*\) => \(.*\)}/\1/g'                                   \
605		| html_encode | awk -v flist="${git_commit_files}" -v base="//${1}" '
606	BEGIN {
607		marker=""; files=0; split(flist, farr, "\n");
608		for (i in farr) {
609			split(farr[i], ftmp, ":");
610			farr[i,1] = substr(ftmp[1], 1, 1);
611			farr[i,2] = ftmp[2];
612			farr[i,3] = ftmp[3];
613		}
614	}
615	{
616		switch (NR) {
617		case 1:
618			marker=$0
619			printf "<pre>\n"
620			printf "<b>commit</b>: <a href=\"%s/commit/%s.html\">%s</a>\n",base,$0,$0
621		break
622		case 2:
623			printf "<b>parent</b>: <a href=\"%s/commit/%s.html\">%s</a>\n",base,$0,$0
624		break
625		case 3:
626			printf "<b>author</b>: %s",$0
627		break
628		case 4:
629			if ($0 != "") { printf " &lt;<a href=\"mailto:%s\">%s</a>&gt;",$0,$0 }
630			printf "\n"
631		break
632		case 5:
633			printf "<b>date</b>:   %s\n",$0
634			printf "</pre>\n"
635		break
636		case 6:
637			printf "<pre class=\"body\">\n"
638		default:
639			if (files) {
640				for (i in farr) {
641					if ($1 == farr[i,2]) {
642						printf "<tr>"
643						printf "<td>%s</td><td><a href=\"#f%d\">%s</a>",farr[i,1],i,farr[i,2]
644						if (farr[i,3] != "") {
645							printf " &rarr; <a href=\"#f%d\">%s</a>",i,farr[i,3]
646						}
647						printf "</td>",$3
648						printf "<td>%s</td>",$3
649						printf "<td><span class=\"i\">"
650						p=1
651						for (j = 1; j <= length($4); j++) {
652							if (p && substr($4, j, 1) != "+") {
653								p=0; printf "</span><span class=\"d\">"
654							}
655							printf "%s",substr($4,j,1)
656						}
657						printf "</span></td>"
658						print "</tr>"
659						next
660					}
661				}
662				sub(/^[ \t\r\n]+/, "", $0)
663				printf "</table>\n%s\n",$0
664			} else {
665				if (marker != "" && marker == $0) { printf "</pre>\n<table>\n"; files=1 }
666				else { print }
667			}
668		break
669		}
670	}'
671	echo "<hr />"
672	git -C "${1}" show "${2}" --format="" | html_encode | awk -v flist="${git_commit_files}" '
673	BEGIN {
674		indiff=0; files=0; h=0; l=0 split(flist, farr, "\n");
675		for (i in farr) {
676			split(farr[i], ftmp, ":");
677			farr[i,1] = ftmp[1];
678			farr[i,2] = ftmp[2];
679		}
680		print "<pre>"
681	}
682	/^diff --git/ {
683		indiff=1
684		if (match($0, /^diff --git a\/(.*) b\/(.*)$/, m)) {
685			for (i in farr) {
686				if (m[1] == farr[i,2]) {
687					printf "<b>diff --git"
688					printf " a/<a id=\"f%d\" href=\"#f%d\">%s</a>",i,i,m[1]
689					printf " b/<a href=\"#f%d\">%s</a>",i,m[2]
690					printf "</b>\n"
691					if (m[1] != m[2]) {
692						printf "<b class=\"r\">rename %s &rarr; ",m[1]
693						printf "%s</b>\n",m[2]
694					}
695					next
696				}
697			}
698		}
699		next
700	}
701	/^@@/ {
702		indiff=0
703		printf "<a href=\"#h%d\" id=\"h%d\" class=\"h\">%s</a>\n",h,h++,$0
704		next
705	}
706	/^\+.*$/ {
707		if (indiff) { next }
708		printf "<a href=\"#l%d\" id=\"l%d\" class=\"i\">%s</a>\n",l,l++,$0
709		next
710	}
711	/^\-.*$/ {
712		if (indiff) { next }
713		printf "<a href=\"#l%d\" id=\"l%d\" class=\"d\">%s</a>\n",l,l++,$0
714		next
715	}
716	{
717		if (indiff) { next }
718		print
719	}
720	END {
721		print "</pre>"
722	}'
723}
724
725render_git_file() {
726	printf '\t<span class="git-file">%s</span>\n\t<hr />\n' "${2}"
727	if git -C "${1}" diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904          \
728		--numstat HEAD -- "${2}" | grep '^-' >/dev/null 2>&1; then
729		printf '\t%s\n' "binary file."
730	else
731		git -C "${1}" cat-file "HEAD:${2}" -p                               \
732		| html_encode                                                       \
733		| awk '
734			BEGIN {
735				print "<pre>"
736			}
737
738			{
739				print "<a class=\"line\" href=\"#l" NR "\" id=\"l" NR "\">" NR "</a>" $0
740			}
741
742			END {
743				print "</pre>"
744			}
745		'
746	fi
747}
748
749render_git_repo() {
750	repo_path="${SITE_GIT_REPO_ROOT}/$2"
751	repo_path_head="${1}/${2}/head.html.tmp"
752	repo_path_log="${1}/${2}/log.html.tmp"
753	repo_path_files="${1}/${2}/files.html.tmp"
754	repo_path_file="${1}/${2}/file"
755	repo_path_commit="${1}/${2}/commit"
756	repo_path_tags="${1}/${2}/tags.html.tmp"
757	repo_path_archive="${1}/${2}/archive"
758	repo_name="${2%.*}"
759	repo_description=""
760
761	rsync -a --delete-before "${repo_path}/" "${1}/${2##*/}"
762	git -C "${1}/${2##*/}" --bare update-server-info
763	ln -s "refs" "${1}/${2##*/}/info/refs?service=git-upload-pack"
764
765	repo_description="$(< "${1}/${2}"/description html_encode)"
766
767	# create archive files (for each tag)
768	mkdir "${repo_path_archive}"
769	git -C "${1}/${2}" tag                                                  \
770		| xargs -I{} git -C "${1}/${2}" archive                             \
771			--format=tar.gz --prefix="${repo_name}-{}/"                     \
772			-o "archive/${repo_name}-{}.tar.gz" "{}"
773
774	# create preview files
775	mkdir "${repo_path_file}"
776	git -C "${1}/${2}" ls-tree                                              \
777		-r --format="%(objectmode)%x0a%(path)" HEAD                         \
778		| grep '^100[0-9][0-9][0-9]$' -A1                                   \
779		| grep -v '^--$\|^100[0-9][0-9][0-9]$'                              \
780		| while read -r file; do
781			file_path="$(echo "${repo_path_file}/${file}" | fix_dot_file)"
782			mkdir -p "${file_path%/*}"
783			render_git_file "${1}/${2}" "${file}" > "${file_path}.html.tmp"
784		done
785
786	# create commit files
787	mkdir "${repo_path_commit}"
788	git -C "${1}/${2}" log --pretty="format:%H"                             \
789		| grep .                                                            \
790		| while read -r file; do
791			file_path="$(echo "${repo_path_commit}/${file}")"
792			mkdir -p "${file_path%/*}"
793			render_git_commit "${1}/${2}" "${file}" > "${file_path}.html.tmp"
794		done
795
796	# render common html head
797	awk                                                                     \
798		-v var_site="$(awk_safe "${1}")"                                    \
799		-v var_repo="$(awk_safe "${2}")"                                    \
800		-v var_logo="$(awk_safe "${SITE_ICON_SVG}")"                        \
801		-v var_name="$(awk_safe "${repo_name}")"                            \
802		-v var_description="$(awk_safe "${repo_description}")"              \
803		-v var_menu="$(
804			printf '<a href="//%s/log.html">Log</a>' "${1}/${2}"
805			printf ' | <a href="//%s/files.html">Files</a>' "${1}/${2}"
806			git -C "${1}/${2}" describe --tags >/dev/null 2>&1 &&
807			printf ' | <a href="//%s/tags.html">Tags</a>' "${1}/${2}"
808			git -C "${1}/${2}" show HEAD:README >/dev/null 2>&1 &&          \
809			printf ' | <a href="//%s/file/README.html">README</a>' "${1}/${2}"
810			git -C "${1}/${2}" show HEAD:LICENSE >/dev/null 2>&1 &&         \
811			printf ' | <a href="//%s/file/LICENSE.html">LICENSE</a>' "${1}/${2}"
812		)"                                                                  \
813	'
814		{
815			gsub(/\{:site:\}/, var_site)
816			gsub(/\{:repo:\}/, var_repo)
817			gsub(/\{:logo:\}/, var_logo)
818			gsub(/\{:name:\}/, var_name)
819			gsub(/\{:description:\}/, var_description)
820			gsub(/\{:menu:\}/, var_menu)
821			print
822		}
823	' "${CFG_GIT_HEAD_HTML}" > "${repo_path_head}"
824
825	# render log
826	git -C "${1}/${2}" log                                                  \
827		--pretty="format:%ai%n%s%n%an%n%H"                                  \
828	| html_encode                                                           \
829	| awk '
830		BEGIN {
831			printf "\t<table id=\"log\">\n"
832			printf "\t\t<tr class=\"nohi\">"
833			printf "<td>Date</td>"
834			printf "<td>Commit message</td>"
835			printf "<td>Author</td>"
836			printf "<td>Commit</td>"
837			printf "</tr>\n"
838			printf "\t\t<tbody>\n"
839		}
840
841		{
842			entry[(NR-1) % 4] = $0
843			if (NR % 4 == 0) {
844				printf "\t\t\t<tr>"
845				for (i = 0; i < 4; i++) {
846					if (i == 1) {
847						printf "<td><a href=\"commit/%s.html\">%s</a></td>",entry[3],entry[i]
848					} else if (i == 3) {
849						printf "<td><a href=\"commit/%s.html\">%*.*s</a></td>",entry[i],8,8,entry[i]
850					} else {
851						printf "<td>%s</td>",entry[i]
852					}
853				}
854				printf "</tr>\n"
855			}
856		}
857
858		END {
859			printf "\t\t</tbody>\n"
860			printf "\t</table>\n"
861		}
862	' > "${repo_path_log}"
863
864	# render files
865	git -C "${1}/${2}" ls-tree                                              \
866		-r --format="%(objectmode)%x0a%(path)%x0a%(objectsize)" HEAD        \
867	| html_encode                                                           \
868	| fix_dot_file                                                          \
869	| awk '
870		function dotrep(data)
871		{
872			output = data
873			gsub(/\/_\./, "/.", output)
874			gsub(/^_\./, ".", output)
875			return output
876		}
877
878		function oct2sym(data)
879		{
880			type = substr(data, 0, 3)
881			if (type == "100") {
882				type = "-"
883			} else if (type == "060") {
884				type = "b"
885			} else if (type == "020") {
886				type = "c"
887			} else if (type == "040") {
888				type = "d"
889			} else if (type == "010") {
890				type = "p"
891			} else if (type == "120") {
892				type = "l"
893			} else if (type == "140") {
894				type = "s"
895			} else {
896				type = "?"
897			}
898
899			sym = substr(data, 4, 3)
900			gsub("0", "---", sym)
901			gsub("1", "--x", sym)
902			gsub("2", "-w-", sym)
903			gsub("3", "-wx", sym)
904			gsub("4", "r--", sym)
905			gsub("5", "r-x", sym)
906			gsub("6", "rw-", sym)
907			gsub("7", "rwx", sym)
908			return type sym
909		}
910
911		BEGIN {
912			printf "\t<table id=\"files\">\n"
913			printf "\t\t<tr class=\"nohi\">"
914			printf "<td>Mode</td>"
915			printf "<td>Name</td>"
916			printf "<td>Size</td>"
917			printf "</tr>\n"
918			printf "\t\t<tbody>\n"
919		}
920
921		{
922			entry[(NR-1) % 3] = $0
923			if (NR % 3 == 0) {
924				printf "\t\t\t<tr>"
925				for (i = 0; i < 3; i++) {
926					if (i == 1 && substr(entry[0], 0, 3) == "100") {
927						printf "<td><a href=\"file/%s.html\">%s</a></td>", entry[i], dotrep(entry[i])
928					} else {
929						printf "<td>%s</td>", i == 0 ? oct2sym(entry[i]) : entry[i]
930					}
931				}
932				printf "</tr>\n"
933			}
934		}
935
936		END {
937			printf "\t\t</tbody>\n"
938			printf "\t</table>\n"
939		}
940	' > "${repo_path_files}"
941
942	# render tags
943	git -C "${1}/${2}" log                                                  \
944		--no-walk --tags --pretty="format:%S%n%ai%n%an%n%h"                 \
945	| html_encode                                                           \
946	| awk '
947		BEGIN {
948			printf "\t<table id=\"tags\">\n"
949			printf "\t\t<tr class=\"nohi\">"
950			printf "<td>Name</td>"
951			printf "<td>Date</td>"
952			printf "<td>Author</td>"
953			printf "<td>Commit</td>"
954			printf "</tr>\n"
955			printf "\t\t<tbody>\n"
956		}
957
958		{
959			entry[(NR-1) % 4] = $0
960			if (NR % 4 == 0) {
961				printf "\t\t\t<tr>"
962				for (i = 0; i < 4; i++) {
963					if (i == 0) {
964						printf "<td><a href=\"./archive/__REPONAME__-%s.tar.gz\">%s</a></td>",entry[i],entry[i]
965					} else {
966						printf "<td>%s</td>",entry[i]
967					}
968				}
969				printf "</tr>\n"
970			}
971		}
972
973		END {
974			printf "\t\t</tbody>\n"
975			printf "\t</table>\n"
976		}
977	' | sed "s/__REPONAME__/${repo_name}/g" > "${repo_path_tags}"
978
979	# create redirection to README if it exists, else symlink to log
980	git -C "${1}/${2}" show HEAD:README >/dev/null 2>&1 &&                  \
981	printf '<meta http-equiv="refresh" content="0; url=%s" />'              \
982		"${repo_path_file##*/}/README.html"                                 \
983		> "${1}/${2}/index.html"
984
985	[ ! -f "${1}/${2}/index.html" ] && ln -s "log.html" "${1}/${2}/index.html"
986}
987
988render_git() {
989	git_repos=
990	git_forks=
991	git_discs=
992	git_buffer=
993	git_pp=
994	git_owner=
995	git_description=
996	git_index="${1}/index.html"
997
998	for repo in "${SITE_GIT_REPO_ROOT}"/*; do
999		git_pp="${repo##*/}"
1000		git_pp="${git_pp%.*}"
1001		print_loading "Rendering repo ${git_pp}"
1002		git_owner="$(< "${repo}"/owner html_encode)"
1003		git_description="$(< "${repo}"/description html_encode)"
1004		git_buffer=$(
1005			printf '<tr><td><a href="%s">%s</a></td><td>%s</td><td>%s</td><td>%s</td></tr>' \
1006				"//${1}/${repo##*/}"                                        \
1007				"${git_pp}"                                                 \
1008				"${git_description}"                                        \
1009				"${git_owner}"                                              \
1010				"$(git -C "${repo}" log -1 --format=%ai)")
1011
1012		if [ -f "$repo/fork" ]; then
1013			git_forks="$(printf '%s%s' "${git_forks}" "${git_buffer}")"
1014		elif [ -f "$repo/discontinued" ]; then
1015			git_discs="$(printf '%s%s' "${git_discs}" "${git_buffer}")"
1016		else
1017			git_repos="$(printf '%s%s' "${git_repos}" "${git_buffer}")"
1018		fi
1019
1020		render_git_repo "${1}" "${repo##*/}"
1021		print_done
1022	done
1023
1024	awk                                                                     \
1025		-v var_author="$(awk_safe "${SITE_AUTHOR}")"                        \
1026		-v var_title="$(awk_safe "Repositories")"                           \
1027		-v var_favicon="$(awk_safe "${SITE_ICON_PNG}")"                     \
1028		-v var_stylesheet="$(awk_safe "${SITE_CSS}")"                       \
1029		-v var_logo="$(awk_safe "${SITE_ICON_SVG}")"                        \
1030		-v var_repos="$(awk_safe "${git_repos}" | sed 's/<tr>/\n\0/2g')"    \
1031		-v var_forks="$(awk_safe "${git_forks}" | sed 's/<tr>/\n\0/2g')"    \
1032		-v var_discs="$(awk_safe "${git_discs}" | sed 's/<tr>/\n\0/2g')"    \
1033	'
1034		/\{:repos:\}/{
1035			padding=$0
1036			gsub(/{:.*:}$/, "", padding)
1037			gsub(/\n/, "\n" padding, var_repos)
1038		}
1039
1040		/\{:forks:\}/{
1041			padding=$0
1042			gsub(/{:.*:}$/, "", padding)
1043			gsub(/\n/, "\n" padding, var_forks)
1044		}
1045
1046		/\{:discs:\}/{
1047			padding=$0
1048			gsub(/{:.*:}$/, "", padding)
1049			gsub(/\n/, "\n" padding, var_dics)
1050		}
1051
1052		{
1053			gsub(/\{:author:\}/, var_author)
1054			gsub(/\{:title:\}/, var_title)
1055			gsub(/\{:favicon:\}/, var_favicon)
1056			gsub(/\{:stylesheet:\}/, var_stylesheet)
1057			gsub(/\{:logo:\}/, var_logo)
1058			gsub(/\{:repos:\}/, var_repos)
1059			gsub(/\{:forks:\}/, var_forks)
1060			gsub(/\{:discs:\}/, var_discs)
1061			print
1062		}
1063	' "${CFG_GIT_REPOS_HTML}" > "${git_index}"
1064
1065	# complete html-files from html.tmp files
1066	find "${1}" -mindepth 2 -type f -name "*.html.tmp" | while read -r file; do
1067		[ "${file##*/}" = "head.html.tmp" ] && continue
1068		{
1069			awk '1;/<body>/{exit}' "${git_index}"
1070			cat "${file%%.git/*}.git/head.html.tmp"
1071			cat "${file}"
1072			awk '/<\/body>/,0' "${git_index}"
1073		} > "${file%.*}"
1074	done
1075
1076	# remove all html.tmp files
1077	find "${1}" -mindepth 2 -type f -name "*.html.tmp" -exec rm -f {} \;
1078}
1079
1080render_git_commits() {
1081	_tmp_file="$(mktemp "${TMPDIR:-/tmp/}$(basename "$0").repolog.XXXXXX")"
1082
1083	for repo in "${SITE_GIT_REPO_ROOT}"/*; do
1084		a=${repo##*/}
1085		c="//${1}/git/${a}/commit"
1086		a="<a href=\"//${1}/git/${a}\">${a%.*}</a>"
1087		git -C "${repo}" log -n "${SITE_GIT_COMMIT_COUNT}"                  \
1088			--no-merges                                                     \
1089			--pretty="format:%at:%ai [$a] <a href=\"$c/%H.html\">%s</a>"
1090		echo
1091	done                                                                    \
1092	| sort -r                                                               \
1093	| sed "${SITE_GIT_COMMIT_COUNT}q"                                       \
1094	| sed -e 's/^[^:]*://g'                                                 \
1095	| awk -v var_domain="$1" '
1096		BEGIN {
1097			print "<ul class=\"repo-log\">";
1098		}
1099
1100		{
1101			printf "<li><span class=\"log-date\">%s %s %s</span>",$1,$2,$3;
1102			$1=$2=$3="";
1103			$0=$0;
1104		}
1105
1106		NF=NF {
1107			printf "%s</li>\n",$0
1108		}
1109
1110		END {
1111			printf "<li>[<a href=\"//%s/git/\">...</a>]</li></ul>\n",var_domain
1112		}
1113	' > "${_tmp_file}"
1114
1115	find "${1}" -type f -name 'index.html' -exec                            \
1116		sed -i {} -e "
1117			/^.*<!--placeholder:${SITE_GIT_COMMIT_PH}-->.*$/ {
1118				r ${_tmp_file}
1119				d
1120			}
1121		" \;
1122
1123	rm -f "${_tmp_file}"
1124}
1125
1126generate_sitemap() {
1127	_sitemap="${1}/pub/sitemap.xml"
1128
1129	awk                                                                     \
1130		-v var_items="$(
1131			find -L "${1}" -type f -name 'index.html'                       \
1132			| html_encode                                                   \
1133			| awk                                                           \
1134				-v format_item="$(cat "${CFG_SITEMAP_XML_ITEM}")\n"         \
1135			'
1136				{
1137					gsub(/[^\/]*$/, "")
1138					printf format_item, $0
1139				}
1140			' | awk_safe
1141		)"                                                                  \
1142	'
1143		{
1144			gsub(/\{:items:\}/, var_items)
1145			print
1146		}
1147	' "${CFG_SITEMAP_XML}" > "${_sitemap}"
1148}
1149
1150main() {
1151	# check if build is possible
1152	if [ "$1" = "check" ]; then
1153		[ -d "${SITE_GIT_REPO_ROOT}" ] || exit 50
1154	fi
1155
1156	# make sure both arguments, if existing, are directories
1157	[ -n "$1" ] && [ ! -d "$1" ] && return
1158	[ -n "$2" ] && [ ! -d "$2" ] && return
1159
1160	if [ -z "$2" ]; then
1161		print_loading "Running the prerequisite script"
1162		# make sure site/git is removed before rendering (to avoid it in menu)
1163		rm -rf "${1}/git"
1164
1165		# make sure tag pages are removed before creating them
1166		rm -rf "${1}"/articles/tags
1167
1168		# create tags directory
1169		mkdir -p "${1}"/articles/tags
1170		touch "${1}"/articles/tags/.buildignore
1171		echo "index.html" > "${1}"/articles/tags/.assemble
1172		echo ".ds TITLE   Tags" > "${1}"/articles/tags/.metadata
1173
1174		printf '.DIVS wrap-list\n.ULS\n' > "${1}"/articles/tags/index.www
1175		# manage tags
1176		find "${1}"/articles -name .tags -exec cat {} \; | sort -u | while read -r tag
1177		do
1178			tag_safe="$(echo "${tag}" | tr \  _)"
1179			mkdir -p "${1}"/articles/tags/"${tag_safe}"
1180			touch "${1}"/articles/tags/"${tag_safe}"/.buildignore
1181			[ "${tag}" != "${CFG_PINNED_TAG}" ] && \
1182			printf '.URL ../.. Articles\ntagged "%s"\n' "${tag}" > "${1}"/articles/tags/"${tag_safe}"/index.www
1183			echo "{:articles#${tag}:}" >> "${1}"/articles/tags/"${tag_safe}"/index.www
1184			echo "index.html" > "${1}"/articles/tags/"${tag_safe}"/.assemble
1185			echo ".ds TITLE   #${tag}" > "${1}"/articles/tags/"${tag_safe}"/.metadata
1186
1187			if [ "${tag}" != "${CFG_PINNED_TAG}" ]; then
1188				# append tag to tags page
1189				printf '.LI\n.ARTTAG "%s" "%s" "%s"\n'                      \
1190					"${tag_safe}" "${tag}"                                  \
1191					"$(grep "^${tag}$" "${1}"/articles/*/.tags | wc -l)"    \
1192					>> "${1}"/articles/tags/index.www
1193			fi
1194		done
1195		printf '.ULE\n' >> "${1}"/articles/tags/index.www
1196		printf '.DIVE\n' >> "${1}"/articles/tags/index.www
1197		print_done
1198
1199		# main render, executes sub render (see below)
1200		find "$1" -depth -type d                                            \
1201			-exec test -e '{}/index.www' \;                                 \
1202			-exec "$0" "$1" {} \;
1203
1204		# render git commits into place holders
1205		print_loading "Rendering git commits"
1206		render_git_commits "$1"
1207		print_done
1208
1209		# render git
1210		[ "${SKIPGIT-SKIP}" = "SKIP" ] && render_git "git.${1}"
1211
1212		# move git.site to site/git
1213		cp -r "git.${1}" "${1}/git"
1214
1215		# create symlinks for each repo, as such: {repo} -> {repo}.git
1216		find "${1}/git" -type d -name "*.git"                               \
1217			-execdir sh -c 'ln -s "${1}" "${1%.*}"' sh {} \;
1218
1219		# translate git.site to site/git
1220		print_loading "Translate git site into ./git"
1221		find "${1}/git" -type f -name "*.html" | while read -r file; do
1222			sed -i "s,\"//\[site\]/,\"//[site]/git/,g" "$file"
1223			sed -i "s,\"//git.${1}/,\"//${1}/git/,g" "$file"
1224			sed -i "s,https://git.${1}/,https://${1}/git/,g" "$file"
1225			sed -i "s,\"//\[root\]/,\"//[site]/,g" "$file"
1226		done
1227		print_done
1228
1229		# convert absolute paths to relative, so that they work with IPFS
1230		print_loading "Converting absolute paths to relative"
1231		find "${1}" -type f -name "*.html" | while read -r file; do
1232			count="$(echo "$file" | tr -cd '/' | wc -c)"
1233			sed -i "s,\"//\(${1}\|\[site\]\)/,\"$(
1234					seq -f "../%g" -s '' 2 "$count" | sed 's/[0-9]//g'
1235				),g" "$file"
1236
1237			# remove redundant prefix from references
1238			grep -o '="../[^"]*"' "$file"                                   \
1239			| sed -e 's/^="//g' -e 's/"$//g' | while read -r path; do
1240				rel="$(realpath --relative-to="${file%/*}" "${file%/*}/${path}")"
1241				rel="$(echo $rel | sed                                      \
1242					-e 's/\./\\./g'                                         \
1243					-e 's/\&/\\&/g'                                         \
1244				)"
1245				ref="$(echo $path | sed                                     \
1246					-e 's/\./\\./g'                                         \
1247					-e 's/\&/\\&/g'                                         \
1248				)"
1249				sed "s,=\"$ref\",=\"$rel\",g" -i "$file"
1250			done
1251
1252		done
1253		print_done
1254
1255		# generate sitemaps
1256		print_loading "Generating sitemaps"
1257		generate_sitemap "${1}"
1258		print_done
1259	elif [ -n "$2" ]; then
1260		# sub render
1261		render_main "$1" "$2"
1262	fi
1263}
1264
1265main "${1:-$SITE_DOMAIN}" "$2"