<commit_before>{{ define "title" }}{{.Repo.Slug}} · {{ .Commit.HashShort }}{{ end }}

{{ define "content" }}

	<div class="subhead">
		<div class="container">
			<ul class="nav nav-tabs pull-right">
				<li class="active"><a href="/{{.Repo.Slug}}/commit/{{ .Commit.Hash }}">{{ .Commit.HashShort }}</a></li>
				<li><a href="/{{.Repo.Slug}}">Commits</a></li>
				<li><a href="/{{.Repo.Slug}}/settings">Settings</a></li>
			</ul> <!-- ./nav -->
			<h1>
				<span>{{.Repo.Name}}</span>
				<small>{{.Repo.Owner}}</small>
			</h1>
		</div><!-- ./container -->
	</div><!-- ./subhead -->

	<div class="container">
		<div class="alert alert-build-{{ .Build.Status }}">
			<a href="/{{.Repo.Slug}}/commit/{{.Commit.Hash }}" class="btn btn-{{ .Build.Status }}"></a>
			{{ if .Commit.PullRequest }}
			<span>opened pull request <span># {{ .Commit.PullRequest }}</span></span>
			{{ else }}
			<span>commit <span>{{ .Commit.HashShort }}</span> to <span>{{.Commit.Branch}}</span> branch</span>
			{{ end }}
		</div>
		<div class="build-details container affix-top" data-spy="affix" data-offset-top="248">
			<div class="build-summary">
				<dt>Status</dt>
				<dd>{{.Build.Status}}</dd>
				<dt>Started</dt>
				<dd><span class="timeago" title="{{ .Build.StartedString }}"></span></dd>
				<dt>Duration</dt>
				<dd>{{ if .Build.IsRunning }}--{{else}}{{ .Build.HumanDuration }}{{end}}</dd>
			</div>
			<img src="{{.Commit.Image}}?d=identicon">
			<div class="commit-summary">
				<dt>Commit</dt>
				<dd><u>{{ .Commit.HashShort }}</u></dd>
				<dt>Committer</dt>
				<dd>{{ .Commit.Author }}</dd>
				<dt>Message</dt>
				<dd>{{ .Commit.Message }}</dd>
			</div>
		</div>
		<pre id="stdout"></pre>
		<span id="follow">Follow</span>
	</div><!-- ./container -->
{{ end }}

{{ define "script" }}
	<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.1.0/jquery.timeago.js"></script>
	<script>
		window.autofollow = false;
		$(document).ready(function() {
			$(".timeago").timeago();
			$("#follow").bind("click", function(ev) {
				if (window.autofollow) {
					window.autofollow = false;
					$("#follow").text("Follow");
				} else {
					window.autofollow = true;
					$("#follow").text("Stop following");
				}
			});
		});
	</script>

	<script>
		var re = /\u001B\[([0-9]+;?)*[Km]/g;

		var styles = new Array();
		var formatLine = function(s) {
			// Check for newline and early exit?
			s = s.replace(/</g, "&lt;");
			s = s.replace(/>/g, "&gt;");

			var final = "";
			var current = 0;
			while (m = re.exec(s)) {	
					var part = s.substring(current, m.index+1);
					current = re.lastIndex;

					var token = s.substr(m.index, re.lastIndex - m.index);
					var code = token.substr(2, token.length-2);

					var pre = "";
					var post = "";

					switch (code) {
					case 'm': 
					case '0m':
						var len = styles.length;
						for (var i=0; i < len; i++) {
							styles.pop();
							post += "</span>"
						}
						break;
					case '30;42m': pre = '<span style="color:black;background:lime">'; break;
					case '36m':
					case '36;1m': pre = '<span style="color:cyan;">'; break;
					case '31m':
					case '31;31m': pre = '<span style="color:red;">'; break;
					case '33m': 
					case '33;33m': pre = '<span style="color:yellow;">'; break;
					case '32m':
					case '0;32m': pre = '<span style="color:lime;">'; break;
					case '90m': pre = '<span style="color:gray;">'; break;
					case 'K': 
					case '0K': 
					case '1K':
					case '2K': break;
					}		

					if (pre !== "") {
						styles.push(pre);
					}

					final += part + pre + post;
			}

			var part = s.substring(current, s.length);
			final += part;
			return final;
		};
	</script>

	<script>
	{{ if .Build.IsRunning }}
		var outputBox = document.getElementById('stdout');
		var outputWS = new WebSocket((window.location.protocol=='http:'?'ws':'wss')+'://'+window.location.host+'/feed?token='+{{ .Token }});
		outputWS.onopen = function () { console.log('output websocket open'); };
		outputWS.onerror = function (e) { console.log('websocket error: ' + e); };
		outputWS.onclose = function (e) { window.location.reload(); };
		outputWS.onmessage = function (e) { 
			outputBox.innerHTML += formatLine(e.data);
			if (window.autofollow) {
				window.scrollTo(0, document.body.scrollHeight);
			}
		};
	{{ else }} 
		$.get("/{{ .Repo.Slug }}/commit/{{ .Commit.Hash }}/build/{{ .Build.Slug }}/out.txt", function( data ) {
			$( "#stdout" ).html(formatLine(data));
		});
	{{ end }}
	</script><commit_msg>logline output buffers rather than updating on every ws message<commit_after>{{ define "title" }}{{.Repo.Slug}} · {{ .Commit.HashShort }}{{ end }}

{{ define "content" }}

	<div class="subhead">
		<div class="container">
			<ul class="nav nav-tabs pull-right">
				<li class="active"><a href="/{{.Repo.Slug}}/commit/{{ .Commit.Hash }}">{{ .Commit.HashShort }}</a></li>
				<li><a href="/{{.Repo.Slug}}">Commits</a></li>
				<li><a href="/{{.Repo.Slug}}/settings">Settings</a></li>
			</ul> <!-- ./nav -->
			<h1>
				<span>{{.Repo.Name}}</span>
				<small>{{.Repo.Owner}}</small>
			</h1>
		</div><!-- ./container -->
	</div><!-- ./subhead -->

	<div class="container">
		<div class="alert alert-build-{{ .Build.Status }}">
			<a href="/{{.Repo.Slug}}/commit/{{.Commit.Hash }}" class="btn btn-{{ .Build.Status }}"></a>
			{{ if .Commit.PullRequest }}
			<span>opened pull request <span># {{ .Commit.PullRequest }}</span></span>
			{{ else }}
			<span>commit <span>{{ .Commit.HashShort }}</span> to <span>{{.Commit.Branch}}</span> branch</span>
			{{ end }}
		</div>
		<div class="build-details container affix-top" data-spy="affix" data-offset-top="248">
			<div class="build-summary">
				<dt>Status</dt>
				<dd>{{.Build.Status}}</dd>
				<dt>Started</dt>
				<dd><span class="timeago" title="{{ .Build.StartedString }}"></span></dd>
				<dt>Duration</dt>
				<dd>{{ if .Build.IsRunning }}--{{else}}{{ .Build.HumanDuration }}{{end}}</dd>
			</div>
			<img src="{{.Commit.Image}}?d=identicon">
			<div class="commit-summary">
				<dt>Commit</dt>
				<dd><u>{{ .Commit.HashShort }}</u></dd>
				<dt>Committer</dt>
				<dd>{{ .Commit.Author }}</dd>
				<dt>Message</dt>
				<dd>{{ .Commit.Message }}</dd>
			</div>
		</div>
		<pre id="stdout"></pre>
		<span id="follow">Follow</span>
	</div><!-- ./container -->
{{ end }}

{{ define "script" }}
	<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.1.0/jquery.timeago.js"></script>
	<script>
		window.autofollow = false;
		$(document).ready(function() {
			$(".timeago").timeago();
			$("#follow").bind("click", function(ev) {
				if (window.autofollow) {
					window.autofollow = false;
					$("#follow").text("Follow");
				} else {
					window.autofollow = true;
					$("#follow").text("Stop following");
				}
			});
		});
	</script>

	<script>
		var re = /\u001B\[([0-9]+;?)*[Km]/g;

		var styles = new Array();
		var formatLine = function(s) {
			// Check for newline and early exit?
			s = s.replace(/</g, "&lt;");
			s = s.replace(/>/g, "&gt;");

			var final = "";
			var current = 0;
			while (m = re.exec(s)) {	
					var part = s.substring(current, m.index+1);
					current = re.lastIndex;

					var token = s.substr(m.index, re.lastIndex - m.index);
					var code = token.substr(2, token.length-2);

					var pre = "";
					var post = "";

					switch (code) {
					case 'm': 
					case '0m':
						var len = styles.length;
						for (var i=0; i < len; i++) {
							styles.pop();
							post += "</span>"
						}
						break;
					case '30;42m': pre = '<span style="color:black;background:lime">'; break;
					case '36m':
					case '36;1m': pre = '<span style="color:cyan;">'; break;
					case '31m':
					case '31;31m': pre = '<span style="color:red;">'; break;
					case '33m': 
					case '33;33m': pre = '<span style="color:yellow;">'; break;
					case '32m':
					case '0;32m': pre = '<span style="color:lime;">'; break;
					case '90m': pre = '<span style="color:gray;">'; break;
					case 'K': 
					case '0K': 
					case '1K':
					case '2K': break;
					}		

					if (pre !== "") {
						styles.push(pre);
					}

					final += part + pre + post;
			}

			var part = s.substring(current, s.length);
			final += part;
			return final;
		};
	</script>

	<script>
	{{ if .Build.IsRunning }}
		var outputBox = document.getElementById('stdout');
		var outputWS = new WebSocket((window.location.protocol=='http:'?'ws':'wss')+'://'+window.location.host+'/feed?token='+{{ .Token }});
		outputWS.onopen = function () { console.log('output websocket open'); };
		outputWS.onerror = function (e) { console.log('websocket error: ' + e); };
		outputWS.onclose = function (e) { window.location.reload(); };

		window.requestAnimationFrame = window.requestAnimationFrame ||
			window.webkitRequestAnimationFrame ||
			function(callback, element) {
				return window.setTimeout(function() {
					callback(+new Date());
				}, 1000 / 60);
			};

		var lineBuffer = "";

		outputWS.onmessage = function (e) {
			lineBuffer += formatLine(e.data);
		};

		function updateScreen() {
			if(lineBuffer.length > 0) {
				outputBox.innerHTML += lineBuffer;
				lineBuffer = '';

				if (window.autofollow) {
					window.scrollTo(0, document.body.scrollHeight);
				}
			}
			requestAnimationFrame(updateScreen);
		}

		requestAnimationFrame(updateScreen);

	{{ else }}
		$.get("/{{ .Repo.Slug }}/commit/{{ .Commit.Hash }}/build/{{ .Build.Slug }}/out.txt", function( data ) {
			$( "#stdout" ).html(formatLine(data));
		});
	{{ end }}
	</script>
{'fraction_non_alphanumeric': 0.23837638376383763, 'fraction_numerical': 0.011491829204006326, 'mean_word_length': 2.9840403191936162, 'pattern_counts': {'":': 0, '<': 203, '<?xml version=': 0, '>': 202, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3380514', 'n_tokens_mistral': 4173, 'n_tokens_neox': 3414, 'n_words': 680}