summaryrefslogtreecommitdiffstats
path: root/www/whynotgit.html
diff options
context:
space:
mode:
Diffstat (limited to 'www/whynotgit.html')
-rw-r--r--www/whynotgit.html576
1 files changed, 576 insertions, 0 deletions
diff --git a/www/whynotgit.html b/www/whynotgit.html
new file mode 100644
index 0000000..cc4773c
--- /dev/null
+++ b/www/whynotgit.html
@@ -0,0 +1,576 @@
+<!DOCTYPE html>
+<html><head>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<link href="sqlite.css" rel="stylesheet">
+<title>Why SQLite Does Not Use Git</title>
+<!-- path= -->
+</head>
+<body>
+<div class=nosearch>
+<a href="index.html">
+<img class="logo" src="images/sqlite370_banner.gif" alt="SQLite" border="0">
+</a>
+<div><!-- IE hack to prevent disappearing logo --></div>
+<div class="tagline desktoponly">
+Small. Fast. Reliable.<br>Choose any three.
+</div>
+<div class="menu mainmenu">
+<ul>
+<li><a href="index.html">Home</a>
+<li class='mobileonly'><a href="javascript:void(0)" onclick='toggle_div("submenu")'>Menu</a>
+<li class='wideonly'><a href='about.html'>About</a>
+<li class='desktoponly'><a href="docs.html">Documentation</a>
+<li class='desktoponly'><a href="download.html">Download</a>
+<li class='wideonly'><a href='copyright.html'>License</a>
+<li class='desktoponly'><a href="support.html">Support</a>
+<li class='desktoponly'><a href="prosupport.html">Purchase</a>
+<li class='search' id='search_menubutton'>
+<a href="javascript:void(0)" onclick='toggle_search()'>Search</a>
+</ul>
+</div>
+<div class="menu submenu" id="submenu">
+<ul>
+<li><a href='about.html'>About</a>
+<li><a href='docs.html'>Documentation</a>
+<li><a href='download.html'>Download</a>
+<li><a href='support.html'>Support</a>
+<li><a href='prosupport.html'>Purchase</a>
+</ul>
+</div>
+<div class="searchmenu" id="searchmenu">
+<form method="GET" action="search">
+<select name="s" id="searchtype">
+<option value="d">Search Documentation</option>
+<option value="c">Search Changelog</option>
+</select>
+<input type="text" name="q" id="searchbox" value="">
+<input type="submit" value="Go">
+</form>
+</div>
+</div>
+<script>
+function toggle_div(nm) {
+var w = document.getElementById(nm);
+if( w.style.display=="block" ){
+w.style.display = "none";
+}else{
+w.style.display = "block";
+}
+}
+function toggle_search() {
+var w = document.getElementById("searchmenu");
+if( w.style.display=="block" ){
+w.style.display = "none";
+} else {
+w.style.display = "block";
+setTimeout(function(){
+document.getElementById("searchbox").focus()
+}, 30);
+}
+}
+function div_off(nm){document.getElementById(nm).style.display="none";}
+window.onbeforeunload = function(e){div_off("submenu");}
+/* Disable the Search feature if we are not operating from CGI, since */
+/* Search is accomplished using CGI and will not work without it. */
+if( !location.origin || !location.origin.match || !location.origin.match(/http/) ){
+document.getElementById("search_menubutton").style.display = "none";
+}
+/* Used by the Hide/Show button beside syntax diagrams, to toggle the */
+function hideorshow(btn,obj){
+var x = document.getElementById(obj);
+var b = document.getElementById(btn);
+if( x.style.display!='none' ){
+x.style.display = 'none';
+b.innerHTML='show';
+}else{
+x.style.display = '';
+b.innerHTML='hide';
+}
+return false;
+}
+var antiRobot = 0;
+function antiRobotGo(){
+if( antiRobot!=3 ) return;
+antiRobot = 7;
+var j = document.getElementById("mtimelink");
+if(j && j.hasAttribute("data-href")) j.href=j.getAttribute("data-href");
+}
+function antiRobotDefense(){
+document.body.onmousedown=function(){
+antiRobot |= 2;
+antiRobotGo();
+document.body.onmousedown=null;
+}
+document.body.onmousemove=function(){
+antiRobot |= 2;
+antiRobotGo();
+document.body.onmousemove=null;
+}
+setTimeout(function(){
+antiRobot |= 1;
+antiRobotGo();
+}, 100)
+antiRobotGo();
+}
+antiRobotDefense();
+</script>
+<div class=fancy>
+<div class=nosearch>
+<div class="fancy_title">
+Why SQLite Does Not Use Git
+</div>
+<div class="fancy_toc">
+<a onclick="toggle_toc()">
+<span class="fancy_toc_mark" id="toc_mk">&#x25ba;</span>
+Table Of Contents
+</a>
+<div id="toc_sub"><div class="fancy-toc1"><a href="#introduction">1. Introduction</a></div>
+<div class="fancy-toc2"><a href="#edits">1.1. Edits</a></div>
+<div class="fancy-toc1"><a href="#a_few_reasons_why_sqlite_does_not_use_git">2. A Few Reasons Why SQLite Does Not Use Git</a></div>
+<div class="fancy-toc2"><a href="#git_does_not_provide_good_situational_awareness">2.1. Git does not provide good situational awareness</a></div>
+<div class="fancy-toc2"><a href="#git_makes_it_difficult_to_find_successors_descendents_of_a_check_in">2.2. Git makes it difficult to find successors (descendents)
+of a check-in</a></div>
+<div class="fancy-toc2"><a href="#the_mental_model_for_git_is_needlessly_complex">2.3. The mental model for Git is needlessly complex</a></div>
+<div class="fancy-toc2"><a href="#git_does_not_track_historical_branch_names">2.4. Git does not track historical branch names</a></div>
+<div class="fancy-toc2"><a href="#git_requires_more_administrative_support">2.5. Git requires more administrative support</a></div>
+<div class="fancy-toc2"><a href="#git_provides_a_poor_user_experience">2.6. Git provides a poor user experience</a></div>
+<div class="fancy-toc1"><a href="#a_git_user_s_guide_to_accessing_sqlite_source_code">3. A Git-User's Guide To Accessing SQLite Source Code</a></div>
+<div class="fancy-toc2"><a href="#the_official_github_mirror">3.1. The Official GitHub Mirror</a></div>
+<div class="fancy-toc2"><a href="#web_access">3.2. Web Access</a></div>
+<div class="fancy-toc2"><a href="#fossil_access">3.3. Fossil Access</a></div>
+<div class="fancy-toc2"><a href="#verifying_source_code_integrity">3.4. Verifying Source Code Integrity</a></div>
+<div class="fancy-toc1"><a href="#see_also">4. See Also</a></div>
+</div>
+</div>
+<script>
+function toggle_toc(){
+var sub = document.getElementById("toc_sub")
+var mk = document.getElementById("toc_mk")
+if( sub.style.display!="block" ){
+sub.style.display = "block";
+mk.innerHTML = "&#x25bc;";
+} else {
+sub.style.display = "none";
+mk.innerHTML = "&#x25ba;";
+}
+}
+</script>
+</div>
+
+
+
+
+<h1 id="introduction"><span>1. </span>Introduction</h1>
+
+<p>
+SQLite does not use the
+<a href="https://git-scm.org">Git</a> version control system.
+SQLite uses
+<a href="https://fossil-scm.org/">Fossil</a> instead, which is a
+version control system that was specifically designed
+and written to support SQLite.
+
+</p><p>
+People often wonder why SQLite does not use the
+<a href="https://git-scm.org">Git</a> version control system like everybody
+else.
+This article attempts to answer that question. Also,
+in <a href="#getthecode">section 3</a>,
+this article provides hints to Git users
+about how they can easily access the SQLite source code.
+
+</p><p>
+This article is <u>not</u> a comparison between Fossil
+and Git. See
+<a href="https://fossil-scm.org/fossil/doc/trunk/www/fossil-v-git.wiki">https://fossil-scm.org/fossil/doc/trunk/www/fossil-v-git.wiki</a>
+for one comparison of the two systems. Other third-party
+comparisons are available as well - use a search engine to find them.
+
+</p><p>
+This article is <u>not</u> advocating that you switch your projects
+away from Git. You can use whatever version control system you want.
+If you are perfectly happy with Git, then by all means keep using
+Git. But, if Git is not working well for you or you are wondering
+if it can be improved or if there is something better,
+then maybe try to understand the perspectives presented below.
+Use the insights thus obtained to find or write a different and
+better version control system, or to just make
+improvements to Git itself.
+
+</p><h2 id="edits"><span>1.1. </span>Edits</h2>
+
+<p>
+This article has been revised multiple times in an attempt
+to improve clarity, address concerns and misgivings,
+and to fix errors.
+The complete edit history for this document can be seen at
+<a href="https://sqlite.org/docsrc/finfo/pages/whynotgit.in">https://sqlite.org/docsrc/finfo/pages/whynotgit.in</a>.
+(Usage hint: Click on any two nodes of the graph for a diff.
+BTW, are there any Git web interfaces that offers a similar
+capability?)
+
+</p><h1 id="a_few_reasons_why_sqlite_does_not_use_git"><span>2. </span>A Few Reasons Why SQLite Does Not Use Git</h1>
+
+<h2 id="git_does_not_provide_good_situational_awareness"><span>2.1. </span>Git does not provide good situational awareness</h2>
+
+<p>
+When I want to see what has been happening on SQLite, I visit the
+<a href="https://sqlite.org/src/timeline">timeline</a> and in a single
+screen I see a summary of the latest changes, on all branches.
+In a few clicks, I can drill down as much detail as I
+want. I can even do this from a phone.
+
+</p><p>
+GitHub and GitLab offer nothing comparable. The closest I have
+found is the <a href="https://github.com/sqlite/sqlite/network">network</a>,
+which is slow to render (unless it is already cached), does not
+offer nearly as much details, and scarcely works at all on mobile.
+The <a href="https://github.com/sqlite/sqlite/commits/master">commits</a> view
+of GitHub provides more detail, renders quickly,
+and works on mobile, but only shows a single branch at a time,
+so I cannot easily know if I've seen all of the recent changes.
+And even if GitHub/GitLab did offer better interfaces, both are
+third-party services. They are not a core part of Git. Hence,
+using them introduces yet another dependency into the project.
+
+</p><p>
+I am told that Git users commonly install third-party graphical
+viewers for Git, many of which do a better job of showing recent
+activity on the project. That is great, but these are still
+more third-party applications that must be installed and
+managed separately. Many are platform-specific. (One of the
+better ones, <a href="https://gitup.co/">GitUp</a>, only works on Mac, for
+example.) All require that you first sync your local repository
+then bring up their graphical interface on your desktop. And
+even with all that, I still cannot see what I typically want to
+see without multiple clicks. Checking on project status from
+a phone while away from the office is not an option.
+
+</p><h2 id="git_makes_it_difficult_to_find_successors_descendents_of_a_check_in"><span>2.2. </span>Git makes it difficult to find successors (descendents)
+of a check-in</h2>
+
+<p>
+Git lets you look backwards in time, but not forwards.
+Given some historical check-in, you can see what came before,
+but it is challenging see what came next.
+
+</p><p>
+In contrast, Fossil offers helpful displays such as
+<a href="https://sqlite.org/src/timeline?df=major-release">https://sqlite.org/src/timeline?df=major-release</a>
+to show all check-ins that are derived from the most
+recent major release.
+
+</p><p>
+</p><ul>
+<li>
+<a href="https://sqlite.org/src/timeline?df=major-release">
+All SQLite check-ins derived from the most recent major release</a>
+</li></ul>
+
+
+<p>It is not impossible to find the descendents of a check-in
+in Git. It is merely difficult. For example,
+there is a
+<a href="https://stackoverflow.com/questions/27960605/find-all-the-direct-descendants-of-a-given-commit#27962018">stackoverflow page</a>
+showing the command sequence for finding the descendents of a check-in
+in unix:
+
+</p><div class="codeblock"><pre>git rev-list --all --parents | grep ".\{40\}.*<parent_sha1>.*" | awk '{print $1}'
+</parent_sha1>
+</pre></div>
+
+<p>
+But this is not the same thing. The command above gives
+a list of descendents without showing the branching structure, which
+is important for understanding what happened. And the command only works
+if you have a local clone of the repository; finding the descendents of
+a check-in is not something you can do with web interfaces such
+as GitHub or GitLab.
+
+</p><p>
+This is not really about just finding the descendents of a check-in
+from time to time. The fact that descendents are readily available in
+Fossil means that the information pervades the web pages provided by
+Fossil. One example: Every Fossil check-in information page
+(<a href="https://www.sqlite.org/src/info/ec7addc87f97bcff">example</a>) shows
+a small "Context" graph of the immediate predecessor and successors
+to that check-in. This helps the user maintain better situational
+awareness, and it provides useful capabilities, such as the ability
+click forward to the next check-in in sequence. Another example:
+Fossil easily shows the context around a specific check-in
+(<a href="https://www.sqlite.org/src/timeline?c=2018-03-16&n=10">example</a>)
+which again helps to promote situational awareness and a deeper
+understanding of what is happening in the code. There is a
+<a href="https://fossil-scm.org/fossil/doc/trunk/www/webpage-ex.md">whole page of additional examples</a>
+in the <a href="https://fossil-scm.org/fossil">Fossil documentation</a>.
+
+</p><p>
+All of the above is theoretically possible with Git, given the right extensions
+and tools and using the right commands. But it is not easy to do,
+and so it rarely gets done. Consequently, developers have less awareness
+of what is happening in the code.
+
+</p><h2 id="the_mental_model_for_git_is_needlessly_complex"><span>2.3. </span>The mental model for Git is needlessly complex</h2>
+
+<p>
+The complexity of Git
+distracts attention from the software under development. A user of Git
+needs to keep all of the following in mind:
+</p><ol type="a">
+<li> The working directory
+</li><li> The "index" or staging area
+</li><li> The local head
+</li><li> The local copy of the remote head
+</li><li> The actual remote head
+</li></ol>
+<p>
+Git has commands (and/or options on commands) for moving and
+comparing content between all of these locations.
+
+</p><p>In contrast,
+Fossil users only need to think about their working directory and
+the check-in they are working on. That is 60% less distraction.
+Every developer has a finite number of brain-cycles. Fossil
+requires fewer brain-cycles to operate, thus freeing up
+intellectual resources to focus on the software under development.
+
+</p><p>One user of both Git and Fossil
+<a href="https://news.ycombinator.com/item?id=16806955">writes in HN</a>:
+
+</p><blockquote><i>
+Fossil gives me peace of mind that I have everything ... synced to
+the server with a single command....
+I never get this peace of mind with git.
+</i></blockquote>
+
+<h2 id="git_does_not_track_historical_branch_names"><span>2.4. </span>Git does not track historical branch names</h2>
+
+<p>
+Git keeps the complete DAG of the check-in sequence. But branch
+tags are local information that is not synced and not retained
+once a branch closes.
+This makes review of historical
+branches tedious.
+
+</p><p>
+As an example, suppose a customer asks you:
+"What ever became of that 'prefer-coroutine-sort-subquery' branch
+from two years ago?"
+You might try to answer by consulting the history in
+your version control system, thusly:
+
+</p><ul>
+<li><b>GitHub:</b> <a href="https://github.com/sqlite/sqlite/commits/prefer-coroutine-sort-subquery">https://github.com/sqlite/sqlite/commits/prefer-coroutine-sort-subquery</a>
+</li><li><b>Fossil:</b> <a href="https://sqlite.org/src/timeline?r=prefer-coroutine-sort-subquery">https://sqlite.org/src/timeline?r=prefer-coroutine-sort-subquery</a>
+</li></ul>
+
+<p>
+The Fossil view clearly shows that the branch was eventually merged back into
+trunk. It shows where the branch started, and it shows two occasions where changes
+on trunk were merged into the branch. GitHub shows none of this. In fact, the
+GitHub display is mostly useless in trying to figure out what happened.
+
+</p><p>
+Many readers have recommended various third-party GUIs for Git that
+might do a better job of showing historical development activity. Maybe
+some of them do work better than native Git and/or GitHub, though they
+will all be hampered by the fact that Git does not preserve historical
+branch names across syncs. And even if those other tools are better,
+the fact that it is necessary to go to a third-party tool to get the information
+desired does not speak well of the core system.
+
+</p><h2 id="git_requires_more_administrative_support"><span>2.5. </span>Git requires more administrative support</h2>
+
+<p>
+Git is complex software.
+One needs an installer of some kind to put Git on a developer
+workstation, or to upgrade to a newer version of Git.
+Standing up a Git server is non-trivial, and so most developers
+use a third-party service such as GitHub or GitLab,
+and thus introduce additional dependencies.
+
+</p><p>
+In contrast, Fossil is a single standalone binary which is
+installed by putting it on $PATH. That one binary contains all
+the functionality of core Git and also GitHub and/or GitLab. It
+manages a community server with wiki, bug tracking, and forums,
+provides packaged downloads for consumers, login managements,
+and so forth, with no extra software required. Standing up a
+community server for Fossil takes minutes. And Fossil is efficient.
+A Fossil server will run fine on a $5/month VPS or a Raspberry Pi,
+whereas GitLab and similar require beefier hardware.
+
+</p><p>
+Less administration means that programmers spend more time working
+on the software (SQLite in this case) and less time fussing with
+the version control system.
+
+</p><h2 id="git_provides_a_poor_user_experience"><span>2.6. </span>Git provides a poor user experience</h2>
+
+<p>The following <a href="https://xkcd.com/1597/">https://xkcd.com/1597/</a> cartoon is an
+exaggeration, yet hits close to home:
+
+</p><p>
+<img src="xkcd-git.gif">
+
+</p><p>Let's be real. Few people dispute that Git provides
+a suboptimal user experience. A lot of
+the underlying implementation shows through into the user
+interface. The interface is so bad that there is even a
+parody site that generates
+<a href="https://git-man-page-generator.lokaltog.net/">fake git man pages</a>.
+
+</p><p>Designing software is hard. It takes a lot of focus.
+A good version control system should provide the developer with
+assistance, not frustration. Git has gotten better in this
+regard over the past decade, but it still has a long way to go.
+
+<a name="getthecode"></a>
+</p><h1 id="a_git_user_s_guide_to_accessing_sqlite_source_code"><span>3. </span>A Git-User's Guide To Accessing SQLite Source Code</h1>
+
+<p>
+If you are a devoted Git user, you can still easily access SQLite.
+This section gives some hints on how to do so.
+
+</p><h2 id="the_official_github_mirror"><span>3.1. </span>The Official GitHub Mirror</h2>
+
+<p>
+As of 2019-03-20, there is now an
+<a href="https://github.com/sqlite/sqlite">official Git mirror</a> of the
+SQLite sources on GitHub.
+
+</p><p>The mirror is an incremental export of the
+<a href="https://sqlite.org/src/timeline">canonical Fossil repository</a> for
+SQLite. A cron-job updates the GitHub repository once an hour.
+This is a one-way, read-only code mirror. No pull requests or
+changes are accepted via GitHub. The GitHub repository merely copies
+the content from the Fossil repository. All changes are input via
+Fossil.
+
+</p><p>
+The hashes that identify check-ins and files on the Git mirror are
+different from the hashes in Fossil. There are many reasons for
+this, chief among them that Fossil uses a SHA3-256 hash whereas
+Git uses a SHA1 hash. During export, the original Fossil hash for
+each check-in is added as a footer to check-in comments. To avoid
+confusion, always use the original Fossil hash, not the Git hash,
+when referring to SQLite check-ins.
+
+</p><h2 id="web_access"><span>3.2. </span>Web Access</h2>
+
+<p>
+The <a href="https://sqlite.org/src/timeline">SQLite Fossil Repository</a> contains links
+for downloading a Tarball, ZIP Archive, or <a href="sqlar.html">SQLite Archive</a> for any
+historical version of SQLite. The URLs for these downloads are
+simple and can be incorporated easily into automated tools. The format is:
+
+</p><blockquote>
+<tt>https://sqlite.org/src/tarball/</tt><i>VERSION</i><tt>/sqlite.tar.gz</tt>
+</blockquote>
+
+<p>
+Simply replace <i>VERSION</i> with some description of the version to be
+downloaded. The <i>VERSION</i> can be a prefix of the cryptographic hash
+name of a specific check-in, or the name of a branch (in which case the
+most recent version of the branch is fetched) or a tag for a specific
+check-in like "version-3.23.1":
+
+</p><blockquote>
+<tt>https://sqlite.org/src/tarball/version-3.23.1/sqlite.tar.gz</tt>
+</blockquote>
+
+
+<p>To get the latest release, use "release"
+for <i>VERSION</i>, like this:
+
+</p><blockquote>
+<tt>https://sqlite.org/src/tarball/release/sqlite.tar.gz</tt>
+</blockquote>
+
+<p>
+To get the latest trunk check-in, us "trunk" for <i>VERSION</i>:
+
+</p><blockquote>
+<tt>https://sqlite.org/src/tarball/trunk/sqlite.tar.gz</tt>
+</blockquote>
+
+<p>
+And so forth.
+For ZIP archives and SQLite Archives, simply change the "/tarball/" element
+into either "/zip/" or "/sqlar/", and maybe also change the name of the
+download file to have a ".zip" or ".sqlar" suffix.
+
+</p><h2 id="fossil_access"><span>3.3. </span>Fossil Access</h2>
+
+<p>
+Fossil is easy to install and use. Here are the steps for unix.
+(Windows is similar.)
+
+</p><ol>
+<li>
+Download the self-contained Fossil executable from
+<a href="https://fossil-scm.org/fossil/uv/download.html">https://fossil-scm.org/fossil/uv/download.html</a> and put the executable
+somewhere on your $PATH.
+</li><li><tt>mkdir ~/fossils</tt>
+</li><li><tt>fossil clone https://sqlite.org/src ~/fossils/sqlite.fossil</tt>
+</li><li><tt>mkdir ~/sqlite; cd ~/sqlite</tt>
+</li><li><tt>fossil open ~/fossils/sqlite.fossil</tt>
+</li></ol>
+
+<p>
+At this point you are ready to type "<tt>./configure; make</tt>"
+(or on Windows with MSVC, "<tt>nmake /f Makefile.msc</tt>").
+
+</p><p>
+To change your checkout to a different version of Fossil use
+the "update" command:
+
+</p><blockquote>
+<tt>fossil update </tt><i>VERSION</i>
+</blockquote>
+
+<p>
+Use "trunk" for <i>VERSION</i> to get the latest trunk version of SQLite.
+Or use a prefix of a cryptographic hash name, or the name of some branch
+or tag. See
+<a href="https://fossil-scm.org/fossil/doc/trunk/www/checkin_names.wiki">https://fossil-scm.org/fossil/doc/trunk/www/checkin_names.wiki</a> for more
+suggestions on what names can be used for <i>VERSION</i>.
+
+</p><p>
+Use the "<tt>fossil ui</tt>" command from within the ~/sqlite checkout to
+bring up a local copy of the website.
+
+</p><p>
+Additional documentation on Fossil can be found at
+<a href="https://fossil-scm.org/fossil/doc/trunk/www/permutedindex.html">https://fossil-scm.org/fossil/doc/trunk/www/permutedindex.html</a>
+
+</p><p>
+Do not be afraid to explore and experiment.
+Without a log-in you won't be able to
+push back any changes you make, so you cannot damage the project.
+
+</p><h2 id="verifying_source_code_integrity"><span>3.4. </span>Verifying Source Code Integrity</h2>
+
+<p>
+If you need to verify that the SQLite source code that you have is
+authentic and has not been modified in any way (perhaps by an adversary)
+that can be done using a few simple command-line tools. At the root
+of the SQLite source tree is a file named "manifest". The manifest
+file contains the name of every other file in the source tree together
+with either a SHA1 or SHA3-256 hash for that file. (SHA1 is used for
+older files and SHA3-256 for newer files.) You can write a
+script to extract these hashes and verify them against the source code
+files. The hash name for the check-in is just the SHA3-256 hash of the
+"manifest" file itself, possibly with the last line omitted if the
+last line begins with "# Remove this line..."
+
+</p><h1 id="see_also"><span>4. </span>See Also</h1>
+
+<p>Other pages that talk about Fossil and Git include:
+</p><ul>
+<li><p><a href="https://fossil-scm.org/fossil/doc/trunk/www/fossil-v-git.wiki">Fossil vs. Git</a>
+</p></li><li><p><a href="https://www.fossil-scm.org/fossil/doc/trunk/www/quotes.wiki">What others say about Fossil and Git</a>
+</p></li></ul>
+<p align="center"><small><i>This page last modified on <a href="https://sqlite.org/docsrc/honeypot" id="mtimelink" data-href="https://sqlite.org/docsrc/finfo/pages/whynotgit.in?m=3448c563bf7702abf">2021-12-21 16:55:31</a> UTC </small></i></p>
+