the repository which powers this website
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
{! static int get_num_commits(); static int get_num_branches(); static int get_num_tags(); !}

{% block page_start %}
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>{{ ctx.page.title }}</title>{# ctx.page.title is usually set by prepare_repo_cmd #}
		<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap">
		<link rel="stylesheet" href="/themed.css">
	</head>
	<body class="text-gray-900">
{% endblock %}
{% block repo_header %}
		<header class="bg-gray-50 border-b border-gray-300">{# Repo header #}
			<div class="max-w-[1280px] mx-auto py-4 flex gap-x-1">
				{# Heroicons outline cube #}
				<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="m21 7.5-9-5.25L3 7.5m18 0-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9" /></svg>
				<div class="text-lg"><a href="{{ cgit_rooturl()|attr }}" class="hover:text-blue-600 hover:underline">index</a> / <a href="{! cgit_shared_repolink_url(NULL, NULL, NULL); !}" class="font-semibold hover:text-blue-600 hover:underline">{{ ctx.repo->name }}</a></div>
			</div>
		</header>
{% endblock %}
{% block repo_description_panel %}
			<div class="mb-4">
				{# Description panel #}
				{{ ctx.repo->desc }}
			</div>
{% endblock %}
{% block repo_summary_bar_current_branch %}
				<a href="{! cgit_shared_repolink_url("refs", NULL, NULL); !}" class="flex gap-x-1.5 py-1.5 px-3 bg-gray-50 border border-gray-300 rounded-md hover:bg-gray-100">
					{# Heroicons micro list-bullet #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path d="M3 4.75a1 1 0 1 0 0-2 1 1 0 0 0 0 2ZM6.25 3a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 7.25a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 11.5a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM4 12.25a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM3 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" /></svg>
					<span class="font-semibold self-baseline">{{ ctx.qry.head }}</span>
					{# Heroicons micro chevron-down #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
				</a>
{% endblock %}
{% block repo_summary_bar %}
			<nav class="flex text-sm mb-4">
				{# Repo navigation panel #}
				{! repo_summary_bar_current_branch(); !}
				<a href="{! cgit_shared_repolink_url("log", NULL, NULL); !}" class="flex gap-x-1 py-1.5 px-3 ml-3 rounded-md hover:bg-gray-100">
					{# Heroicons micro clock #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path fill-rule="evenodd" d="M1 8a7 7 0 1 1 14 0A7 7 0 0 1 1 8Zm7.75-4.25a.75.75 0 0 0-1.5 0V8c0 .414.336.75.75.75h3.25a.75.75 0 0 0 0-1.5h-2.5v-3.5Z" clip-rule="evenodd" /></svg>
					{! int num_commits = get_num_commits(); !}
					<span class="font-semibold">{{ num_commits|%d }}</span><span class="font-semibold text-gray-500">Commit{% if num_commits != 1 %}s{% endif %}</span>
				</a>
				<a href="{! cgit_shared_repolink_url("refs", NULL, "heads"); !}" class="flex gap-x-1 py-1.5 px-3 rounded-md hover:bg-gray-100">
					{# Heroicons micro list-bullet #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path d="M3 4.75a1 1 0 1 0 0-2 1 1 0 0 0 0 2ZM6.25 3a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 7.25a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 11.5a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM4 12.25a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM3 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" /></svg>
					{! int num_branches = get_num_branches(); !}
					<span class="font-semibold">{{ num_branches|%d }}</span><span class="font-semibold text-gray-500">Branch{% if num_branches != 1 %}es{% endif %}</span>
				</a>
				<a href="{! cgit_shared_repolink_url("refs", NULL, "tags"); !}" class="flex gap-x-1 py-1.5 px-3 rounded-md hover:bg-gray-100">
					{# Heroicons micro tag #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path fill-rule="evenodd" d="M4.5 2A2.5 2.5 0 0 0 2 4.5v2.879a2.5 2.5 0 0 0 .732 1.767l4.5 4.5a2.5 2.5 0 0 0 3.536 0l2.878-2.878a2.5 2.5 0 0 0 0-3.536l-4.5-4.5A2.5 2.5 0 0 0 7.38 2H4.5ZM5 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd" /></svg>
					{! int num_tags = get_num_tags(); !}
					<span class="font-semibold">{{ num_tags|%d }}</span><span class="font-semibold text-gray-500">Tag{% if num_tags != 1 %}s{% endif %}</span>
				</a>
				<div class="flex-1"></div>
				<!--
				<div class="flex outline-1 outline-gray-300 rounded-lg has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-blue-600">
					{# Search box #}
					<select class="py-1.5 px-2 text-sm text-gray-500 focus:outline-none">
						<option>Log msg</option>
						<option>Author</option>
						<option>Committer</option>
						<option>Range</option>
					</select>
					<input type="text" placeholder="Search commits&hellip;" class="py-1.5 pl-2 text-sm focus:outline-none">
					<button class="py-1.5 px-2 cursor-pointer">
						{# Heroicons micro magnifying-glass #}
						<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="text-gray-700 size-4"><path fill-rule="evenodd" d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z" clip-rule="evenodd" /></svg>
					</button>
				</div>
				-->
				<div class="flex relative">
					{# Code box and panel #}
					<button class="flex gap-x-1.5 py-1.5 px-3 ml-3 bg-blue-500 text-white rounded-md cursor-pointer hover:bg-blue-600 peer">
						{# Code box #}
						{# Heroicons micro code-bracket #}
						<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center"><path fill-rule="evenodd" d="M4.78 4.97a.75.75 0 0 1 0 1.06L2.81 8l1.97 1.97a.75.75 0 1 1-1.06 1.06l-2.5-2.5a.75.75 0 0 1 0-1.06l2.5-2.5a.75.75 0 0 1 1.06 0ZM11.22 4.97a.75.75 0 0 0 0 1.06L13.19 8l-1.97 1.97a.75.75 0 1 0 1.06 1.06l2.5-2.5a.75.75 0 0 0 0-1.06l-2.5-2.5a.75.75 0 0 0-1.06 0ZM8.856 2.008a.75.75 0 0 1 .636.848l-1.5 10.5a.75.75 0 0 1-1.484-.212l1.5-10.5a.75.75 0 0 1 .848-.636Z" clip-rule="evenodd" /></svg>
						<span class="font-semibold">Code</span>
						{# Heroicons micro chevron-down #}
						<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center"><path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
					</button>
					<div class="absolute top-10 right-0 w-[300px] border border-gray-300 rounded-md bg-white p-2 hidden peer-focus:block hover:block">
						{# Code panel #}
						<div class="flex gap-x-1 items-center mb-2">
							{# Heroicons micro command-line #}
							<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path fill-rule="evenodd" d="M2 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4Zm2.22 1.97a.75.75 0 0 0 0 1.06l.97.97-.97.97a.75.75 0 1 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06l-1.5-1.5a.75.75 0 0 0-1.06 0ZM8.75 8.5a.75.75 0 0 0 0 1.5h2.5a.75.75 0 0 0 0-1.5h-2.5Z" clip-rule="evenodd" /></svg>
							<span class="font-semibold text-sm">Clone</span>
						</div>
						<div class="flex outline-1 outline-gray-300 rounded-lg mb-2 has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-blue-600">
							{# Clone URL box #}
							<span class="py-1.5 px-2 text-sm text-gray-500 bg-gray-50 border-r border-gray-300">
								HTTPS
							</span>
							<input type="text" value="{! cgit_add_clone_urls(html_attr); !}" class="repo-clone-url flex-1 py-1.5 pl-2 text-sm focus:outline-none" onfocus="this.select();" readonly>
							<button class="py-1.5 px-2 cursor-pointer" onclick="document.querySelector('.repo-clone-url').select();document.execCommand('copy');">
								{# Heroicons micro clipboard #}
								<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 text-gray-500"><path fill-rule="evenodd" d="M10.986 3H12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h1.014A2.25 2.25 0 0 1 7.25 1h1.5a2.25 2.25 0 0 1 2.236 2ZM9.5 4v-.75a.75.75 0 0 0-.75-.75h-1.5a.75.75 0 0 0-.75.75V4h3Z" clip-rule="evenodd" /></svg>
							</button>
						</div>
						<a href="vscode://vscode.git/clone?url={! cgit_add_clone_urls(html_url_arg); !}" class="flex items-center gap-x-1 hover:text-blue-600 hover:underline mb-2">
							{# Heroicons micro arrow-top-right-on-square #}
							<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path d="M6.22 8.72a.75.75 0 0 0 1.06 1.06l5.22-5.22v1.69a.75.75 0 0 0 1.5 0v-3.5a.75.75 0 0 0-.75-.75h-3.5a.75.75 0 0 0 0 1.5h1.69L6.22 8.72Z" /><path d="M3.5 6.75c0-.69.56-1.25 1.25-1.25H7A.75.75 0 0 0 7 4H4.75A2.75 2.75 0 0 0 2 6.75v4.5A2.75 2.75 0 0 0 4.75 14h4.5A2.75 2.75 0 0 0 12 11.25V9a.75.75 0 0 0-1.5 0v2.25c0 .69-.56 1.25-1.25 1.25h-4.5c-.69 0-1.25-.56-1.25-1.25v-4.5Z" /></svg>
							Open with VS Code
						</a>
						<a href="vscodium://vscode.git/clone?url={! cgit_add_clone_urls(html_url_arg); !}" class="flex items-center gap-x-1 hover:text-blue-600 hover:underline mb-2">
							<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path d="M6.22 8.72a.75.75 0 0 0 1.06 1.06l5.22-5.22v1.69a.75.75 0 0 0 1.5 0v-3.5a.75.75 0 0 0-.75-.75h-3.5a.75.75 0 0 0 0 1.5h1.69L6.22 8.72Z" /><path d="M3.5 6.75c0-.69.56-1.25 1.25-1.25H7A.75.75 0 0 0 7 4H4.75A2.75 2.75 0 0 0 2 6.75v4.5A2.75 2.75 0 0 0 4.75 14h4.5A2.75 2.75 0 0 0 12 11.25V9a.75.75 0 0 0-1.5 0v2.25c0 .69-.56 1.25-1.25 1.25h-4.5c-.69 0-1.25-.56-1.25-1.25v-4.5Z" /></svg>
							Open with VSCodium
						</a>
						<a href="jetbrains://idea/checkout/git?idea.required.plugins.id=Git4Idea&checkout.repo={! cgit_add_clone_urls(html_url_arg); !}" class="flex items-center gap-x-1 hover:text-blue-600 hover:underline">
							<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path d="M6.22 8.72a.75.75 0 0 0 1.06 1.06l5.22-5.22v1.69a.75.75 0 0 0 1.5 0v-3.5a.75.75 0 0 0-.75-.75h-3.5a.75.75 0 0 0 0 1.5h1.69L6.22 8.72Z" /><path d="M3.5 6.75c0-.69.56-1.25 1.25-1.25H7A.75.75 0 0 0 7 4H4.75A2.75 2.75 0 0 0 2 6.75v4.5A2.75 2.75 0 0 0 4.75 14h4.5A2.75 2.75 0 0 0 12 11.25V9a.75.75 0 0 0-1.5 0v2.25c0 .69-.56 1.25-1.25 1.25h-4.5c-.69 0-1.25-.56-1.25-1.25v-4.5Z" /></svg>
							Open with IntelliJ IDEA
						</a>
					</div>
				</div>
			</nav>
{% endblock %}
{% block page_end %}
		<footer class="border-t border-gray-300">
			{# Footer panel #}
			<div class="max-w-[1280px] mx-auto py-4">
				<div class="text-sm text-gray-500">
					{# cgit footer #}
					generated by <a href="https://git.zx2c4.com/cgit/about/" class="hover:text-blue-600 hover:underline">cgit {{ cgit_version }}</a> (<a href="https://git-scm.com/" class="hover:text-blue-600 hover:underline">git {{ git_version_string }}</a>) at
					{{ show_date(time(NULL), 0, cgit_date_mode(DATE_ISO8601)) }}
				</div>
			</div>
		</footer>
	</body>
</html>
{% endblock %}

{!
	static int get_num_commits() {
		int num_commits = 0;
		
		// Based on ui-stats collect_stats
		struct rev_info rev;
		struct commit *commit;
		
		const char *argv[] = {NULL, ctx.qry.head};
		int argc = 2;
		
		repo_init_revisions(the_repository, &rev, NULL);
		rev.abbrev = DEFAULT_ABBREV;
		rev.commit_format = CMIT_FMT_DEFAULT;
		rev.max_parents = 1;
		rev.verbose_header = 1;
		rev.show_root_diff = 0;
		setup_revisions(argc, argv, &rev, NULL);
		prepare_revision_walk(&rev);
		while ((commit = get_revision(&rev)) != NULL) {
			// Process the commit
			num_commits++;
			
			// ?? This causes subsequent walks to return commits with index 0
			//release_commit_memory(the_repository->parsed_objects, commit);
			//commit->parents = NULL;
		}
		reset_revision_walk();
		return num_commits;
	}
	
	static int get_num_branches() {
		struct reflist list;
		list.refs = NULL;
		list.alloc = list.count = 0;
		refs_for_each_branch_ref(get_main_ref_store(the_repository), cgit_refs_cb, &list);
		int num_branches = list.count;
		cgit_free_reflist_inner(&list);
		return num_branches;
	}
	
	static int get_num_tags() {
		struct reflist list;
		list.refs = NULL;
		list.alloc = list.count = 0;
		refs_for_each_tag_ref(get_main_ref_store(the_repository), cgit_refs_cb, &list);
		int num_tags = list.count;
		cgit_free_reflist_inner(&list);
		return num_tags;
	}
!}

{!
	#include "mincrypt_sha256.h"
	
	static void gravatar_url(char *email) {
		// Trim email of whitespace, < and >
		while (isspace(*email) || *email == '<') email++;
		char* strend = email + strlen(email) - 1;
		while (isspace(*strend) || *strend == '>') strend--;  // Now strend points to the last character
		
		// Email to lowercase
		size_t email_len = strend - email + 1;
		char *email_lower = malloc(email_len + 1);  // +1 for null terminator
		for (int i = 0; i < email_len; i++) { email_lower[i] = tolower(email[i]); }
		email_lower[email_len] = '\0';  // For good measure
		
		// Compute hash and print Gravatar link
		uint8_t digest[32];
		SHA256_hash(email, strend - email + 1, digest);
		htmlf(
			"https://gravatar.com/avatar/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
			digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
			digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15],
			digest[16], digest[17], digest[18], digest[19], digest[20], digest[21], digest[22], digest[23],
			digest[24], digest[25], digest[26], digest[27], digest[28], digest[29], digest[30], digest[31]
		);
		
		free(email_lower);
	}
!}