Leaderboard Snippet

I've been using a stack snippet for a while to generate leaderboards for my simpler or more popular code golf challenges. I want to share the code for this snippet here so others can use it more easily as well.

Feel free to put feature requests and bug reports in answers, or let me know in chat.

I'm providing both the minified code (for use in your challenges) and the unminified code (for reviewing/improving the code). Both snippets in this post point to Shotgun Numbers. At the bottom you'll also find the blurb I put in my challenges to explain the header formatting.

Features and Usage

• Shows two leaderboards: one overall leaderboard listing users with their languages by score; and a list of languages used with the best score (and user) per language. The latter is sorted by languages, not by scores (because the language ranking by scores can be read off the main leaderboard).
• Correctly handles ties in the main leaderboard (listing, e.g. 1. 2. 2. 4. ...).
• It takes the last number that is not struck out as the score. This allows keeping previous scores in the header (anywhere) as well as presenting partial scores like Python 2, 34 + 71 = 105.
• Links for language names are allowed and show up in the leaderboard. For the by-language leaderboard, HTML is stripped when comparing languages for equality.
• One user can be chosen (via the OVERRIDE_USER ID in the code) who can override any headers using a comment. This user will usually be the author of the challenge. The comment has to start with Override header: - anything after that will be treated as the new header. If you want to exclude an answer from the leaderboard, just use something like Override header: invalid. This feature is only intended as a last resort to avoid edit wars if some user refuses to use a correct header or delete an invalid answer.

To use the leaderboard in your own challenge, simply copy the snippet and search for the global variable definition of QUESTION_ID and replace it with the ID found in the URL to your question and replace OVERRIDE_USER with your own user ID.

Minified Code

var QUESTION_ID=47338;
var OVERRIDE_USER=8478;
var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;function answersUrl(d){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+d+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(d,e){return"https://api.stackexchange.com/2.2/answers/"+e.join(";")+"/comments?page="+d+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(d){answers.push.apply(answers,d.items),answers_hash=[],answer_ids=[],d.items.forEach(function(e){e.comments=[];var f=+e.share_link.match(/\d+/);answer_ids.push(f),answers_hash[f]=e}),d.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(d){d.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),d.has_more?getComments():more_answers?getAnswers():process()}})}getAnswers();var SCORE_REG=function(){var d=String.rawh\d,e=String.raw\-?\d+\.?\d*,f=String.raw[^\n<>]*,g=String.raw<s>${f}</s>|<strike>${f}</strike>|<del>${f}</del>,h=String.raw[^\n\d<>]*,j=String.raw<[^\n<>]+>;return new RegExp(String.raw<${d}>+String.raw\s*([^\n,]*[^\s,]),.*?+String.raw(${e})+String.raw(?=+String.raw${h}+String.raw(?:(?:${g}|${j})${h})*+String.raw</${d}>+String.raw))}(),OVERRIDE_REG=/^Override\s*header:\s*/i;function getAuthorName(d){return d.owner.display_name}function process(){var d=[];answers.forEach(function(n){var o=n.body;n.comments.forEach(function(q){OVERRIDE_REG.test(q.body)&&(o="<h1>"+q.body.replace(OVERRIDE_REG,"")+"</h1>")});var p=o.match(SCORE_REG);p&&d.push({user:getAuthorName(n),size:+p[2],language:p[1],link:n.share_link})}),d.sort(function(n,o){var p=n.size,q=o.size;return p-q});var e={},f=1,g=null,h=1;d.forEach(function(n){n.size!=g&&(h=f),g=n.size,++f;var o=jQuery("#answer-template").html();o=o.replace("{{PLACE}}",h+".").replace("{{NAME}}",n.user).replace("{{LANGUAGE}}",n.language).replace("{{SIZE}}",n.size).replace("{{LINK}}",n.link),o=jQuery(o),jQuery("#answers").append(o);var p=n.language;p=jQuery("<i>"+n.language+"</i>").text().toLowerCase(),e[p]=e[p]||{lang:n.language,user:n.user,size:n.size,link:n.link,uniq:p}});var j=[];for(var k in e)e.hasOwnProperty(k)&&j.push(e[k]);j.sort(function(n,o){return n.uniq>o.uniq?1:n.uniq<o.uniq?-1:0});for(var l=0;l<j.length;++l){var m=jQuery("#language-template").html(),k=j[l];m=m.replace("{{LANGUAGE}}",k.lang).replace("{{NAME}}",k.user).replace("{{SIZE}}",k.size).replace("{{LINK}}",k.link),m=jQuery(m),jQuery("#languages").append(m)}}
body{text-align:left!important}#answer-list{padding:10px;float:left}#language-list{padding:10px;float:left}table thead{font-weight:700}table td{padding:5px}
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn.sstatic.net/Sites/codegolf/primary.css?v=f52df912b654"> <div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr></tbody> </table> 

Unminified Code

/* Configuration */

var QUESTION_ID = 47338; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 8478; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
jQuery.ajax({
url: answersUrl(answer_page++),
method: "get",
dataType: "jsonp",
crossDomain: true,
success: function (data) {
answers.push.apply(answers, data.items);
answers_hash = [];
answer_ids = [];
data.items.forEach(function(a) {
a.comments = [];
var id = +a.share_link.match(/\d+/);
answer_ids.push(id);
answers_hash[id] = a;
});
if (!data.has_more) more_answers = false;
comment_page = 1;
getComments();
}
});
}

function getComments() {
jQuery.ajax({
url: commentUrl(comment_page++, answer_ids),
method: "get",
dataType: "jsonp",
crossDomain: true,
success: function (data) {
data.items.forEach(function(c) {
if (c.owner.user_id === OVERRIDE_USER)
answers_hash[c.post_id].comments.push(c);
});
if (data.has_more) getComments();
else if (more_answers) getAnswers();
else process();
}
});
}

getAnswers();

var SCORE_REG = (function(){
var headerTag     = String.raw h\d
var score         = String.raw \-?\d+\.?\d* // with negative/floating-point support
var normalText    = String.raw [^\n<>]* // no HTML tag, no newline
var strikethrough = String.raw <s>${normalText}</s>|<strike>${normalText}</strike>|<del>${normalText}</del> var noDigitText = String.raw [^\n\d<>]* var htmlTag = String.raw <[^\n<>]+> return new RegExp( String.raw <${headerTag}>+
String.raw    \s*([^\n,]*[^\s,]),.*?+
String.raw    (${score})+ String.raw (?=+ String.raw ${noDigitText}+
String.raw      (?:(?:${strikethrough}|${htmlTag})${noDigitText})*+ String.raw </${headerTag}>+
String.raw    )
);
})();

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
return a.owner.display_name;
}

function process() {
var valid = [];

answers.forEach(function(a) {
var body = a.body;
a.comments.forEach(function(c) {
if(OVERRIDE_REG.test(c.body))
body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
});

var match = body.match(SCORE_REG);
if (match)
valid.push({
user: getAuthorName(a),
size: +match[2],
language: match[1],
link: a.share_link,
});

});

valid.sort(function (a, b) {
var aB = a.size,
bB = b.size;
return aB - bB
});

var languages = {};
var place = 1;
var lastSize = null;
var lastPlace = 1;
valid.forEach(function (a) {
if (a.size != lastSize)
lastPlace = place;
lastSize = a.size;
++place;

var answer = jQuery("#answer-template").html();
answer = answer.replace("{{PLACE}}", lastPlace + ".")
.replace("{{NAME}}", a.user)
.replace("{{LANGUAGE}}", a.language)
.replace("{{SIZE}}", a.size)
.replace("{{LINK}}", a.link);
answer = jQuery(answer);
jQuery("#answers").append(answer);

var lang = a.language;
lang = jQuery('<i>' + a.language + '</i>').text().toLowerCase();

languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link, uniq: lang};
});

var langs = [];
for (var lang in languages)
if (languages.hasOwnProperty(lang))
langs.push(languages[lang]);

langs.sort(function (a, b) {
if (a.uniq > b.uniq) return 1;
if (a.uniq < b.uniq) return -1;
return 0;
});

for (var i = 0; i < langs.length; ++i)
{
var language = jQuery("#language-template").html();
var lang = langs[i];
language = language.replace("{{LANGUAGE}}", lang.lang)
.replace("{{NAME}}", lang.user)
.replace("{{SIZE}}", lang.size)
.replace("{{LINK}}", lang.link);
language = jQuery(language);
jQuery("#languages").append(language);
}

}
body { text-align: left !important}

#answer-list {
padding: 10px;
float: left;
}

#language-list {
padding: 10px;
float: left;
}

table thead {
font-weight: bold;
}

table td {
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.sstatic.net/Sites/codegolf/primary.css?v=f52df912b654">
<div id="language-list">
<h2>Winners by Language</h2>
<table class="language-list">
<thead>
<tr><td>Language</td><td>User</td><td>Score</td></tr>
</thead>
<tbody id="languages">

</tbody>
</table>
</div>
<div id="answer-list">
<h2>Leaderboard</h2>
<table class="answer-list">
<thead>
<tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
</thead>
<tbody id="answers">

</tbody>
</table>
</div>

<table style="display: none">
<tbody id="answer-template">
<tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr>
</tbody>
</table>
<table style="display: none">
<tbody id="language-template">
<tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr>
</tbody>
</table>

Info Section

You can copy the following Markdown into your challenge as instructions for your participants.

## Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you *can* keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the *last* number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

• It looks like ANSWER_FILTER isn't defined in the minified code, but it is in the unminified code. (The minified code still works though.) Also, what is it? Apr 24, 2015 at 21:33
• Is there a reason why you scrape the Markdown to get the header, instead of parsing the generated HTML? Apr 24, 2015 at 21:53
• @AlexA. The minifier moves definitions around, and ANSWER_FILTER is somewhere at the end. (In fact, QUESTION_ID also ended up there, but I moved that back to the front so it would be easier to find.) Apr 24, 2015 at 22:20
• @NinjaBearMonkey That seemed easier somehow. I guess I could look into using jQuery to fetch the score from the HTML. Apr 24, 2015 at 22:23
• @AlexA. Oh forgot to answer your second question. It's a token sent to the Stack Exchange API which tells the API which fields I want populated in the JSON response (like user ID, timestamp, markdown body, HTML body, etc.). You can create your own here. Apr 24, 2015 at 22:28
• @NinjaBearMonkey Reading the markdown is arguably better because you can look for code blocks with syntax highlighting. HTML mangles highlighted code. On the other hand, not all 4-space indented text is code in markdown, so the regex to match markdown code blocks is trickier if you want to do it right. Apr 27, 2015 at 3:00
• @Calvin'sHobbies That's a good point. I guess there's a trade-off between syntax highlighting and getting the code easily and reliably. Apr 27, 2015 at 11:56
• @Calvin'sHobbies Then again you can also uses <code><pre> in markdown to get a code block. Apr 27, 2015 at 11:57
• Does it handle <del> instead of <s>? May 3, 2015 at 21:14
• @IsmaelMiguel Not really. I don't think I will fix this before changing the entire parsing from regex to jQuery though. No point in patching loads of special cases into that horrible regex if I could just do it right. Also, who would want to type del instead of s anyway? We're still on CodeGolf.SE after all! :P May 3, 2015 at 21:19
• @MartinBüttner Yes, we are. But <del> is the right tag to use. Since an element was removed (in this case, the old byte count). Visually, it makes no difference. May 3, 2015 at 21:27
• Can the \d+ be changed to \-?\d+ so it accepts negative numbers (for bonuses and such)? Oct 3, 2015 at 0:09
• Can you please replace every occurrence of http://api.stackexchange.com/ with //api.stackexchange.com/ (a protocol-relative URL) so the leaderboard works on https://codegolf.stackexchange.com without having to disable mixed content blocking every time? Oct 3, 2015 at 16:16
• @MartinBüttner would you have any objection to the minified snippet markdown being uploaded to pastebin so it can be copied and pasted into posts in a single step? I tried making an answer with the raw markdown showing but <!-- seems to prevent it. Nov 4, 2015 at 11:24
• @Nathaniel A quick fix would be to change the \d+ in that long regex to \d+(?:\.\d+) but I can't tell you off the top of my head how robust that will be. Jan 24, 2016 at 13:41

Feature request: Column rearrangement

In my opinion, the per-language results should be on the left since we emphasize competition within each language. It would simply be a swapping of the current left and right columns.

• I'd put together a prototype but I'm not good with computer May 25, 2016 at 20:41
• Once we see vote support I'm sure there are lots of people who can make the change. If no one volunteers I need some practice myself. May 25, 2016 at 20:42
• May 28, 2018 at 13:12

Layout problem

I'm seeing overlapping of text in some cases. For example, this challenge.

The Winners by Language section starts too far to the left, overlapping the Link from the Leaderboard section.

I'm not sure why this only happens sometimes. Two potential solutions:

1. Shift the Winners by Language section to the right.
2. Use manatwork's suggestion of making the size a link to the solution.

I don't see any ambiguity in making the size a link, as I can't imagine anything else it would link to. It does mean the link is no longer explicit though. Does anyone have any other arguments either way?

Update

Although I am still in favour of making the size a link to the solution, Martin pointed out that this doesn't solve the problem. The Winners by Language section is at a fixed horizontal position, so if the Leaderboard section is too wide due to a long author or language name, there could still be overlap even without a separate link column.

So ideally instead of just shifting the Winners by Language right a bit, it needs to be sensitive to the width of the Leaderboard section. I propose work on this be delayed until after the two sections swap sides, once that proposal gets enough votes.

• The leaderboard script in the challenge you linked tries to include the old stylesheet that is not available anymore since PPCG graduated. I would say, that should be changed in first place. May 26, 2016 at 7:36
• @manatwork I've upvoted your suggestion of a stylesheet redirect to deal with future changes. While we wait to see if that will happen, I guess we just need to edit the snippet to reflect the current stylesheet so it works for now. May 26, 2016 at 11:45
• May 28, 2018 at 13:48

Bug

Although the documentation says that strikeout is supported, it only supports <s> and not <strike> or <del>.

• @MartinEnder any confirmation, disconfirmation, or bug fix down the pipeline? Jun 22, 2016 at 19:21
• Done. (MartinEnder told me that I can edit the post here) May 31, 2018 at 4:56

I would like to suggest a couple of minor changes. In order of appearance:

• JavaScript

• Preserve sign of size by adding -? to the size's group in SCORE_REG (ex: “3” vs. “-3”)

var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(-?\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

• HTML-ify plain text language name, so can jQuery()-fy it and get rid of SGML character entities when getting its text() (eg: “><>” vs. “>&lt;>”)

if (! /<a/.test(lang)) lang = '<i>' + lang + '</i>';

• Transform the langage name in toLowerCase() (eg: “JavaScript” vs. “Javascript”)

lang = jQuery(lang).text().toLowerCase();

• Keep the stripped language with answer data

languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link, uniq: lang};

• Sort by the stripped language name

if (a.uniq > b.uniq) return 1;
if (a.uniq < b.uniq) return -1;

• HTML

• Change the URL of stylesheet to the graduated one

<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/Sites/codegolf/primary.css?v=f52df912b654">

• Use the score as link text (eg: “3” vs. “3 Link”)

<a href="{{LINK}}">{{SIZE}}</a>


Suggested changes applied to the following snippet, configured to show Create output twice the length of the code's score:

/* Configuration */

var QUESTION_ID = 59436; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 41505; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
jQuery.ajax({
url: answersUrl(answer_page++),
method: "get",
dataType: "jsonp",
crossDomain: true,
success: function (data) {
answers.push.apply(answers, data.items);
answers_hash = [];
answer_ids = [];
data.items.forEach(function(a) {
a.comments = [];
var id = +a.share_link.match(/\d+/);
answer_ids.push(id);
answers_hash[id] = a;
});
if (!data.has_more) more_answers = false;
comment_page = 1;
getComments();
}
});
}

function getComments() {
jQuery.ajax({
url: commentUrl(comment_page++, answer_ids),
method: "get",
dataType: "jsonp",
crossDomain: true,
success: function (data) {
data.items.forEach(function(c) {
if (c.owner.user_id === OVERRIDE_USER)
answers_hash[c.post_id].comments.push(c);
});
if (data.has_more) getComments();
else if (more_answers) getAnswers();
else process();
}
});
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(-?\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
return a.owner.display_name;
}

function process() {
var valid = [];

answers.forEach(function(a) {
var body = a.body;
a.comments.forEach(function(c) {
if(OVERRIDE_REG.test(c.body))
body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
});

var match = body.match(SCORE_REG);
if (match)
valid.push({
user: getAuthorName(a),
size: +match[2],
language: match[1],
link: a.share_link,
});

});

valid.sort(function (a, b) {
var aB = a.size,
bB = b.size;
return aB - bB
});

var languages = {};
var place = 1;
var lastSize = null;
var lastPlace = 1;
valid.forEach(function (a) {
if (a.size != lastSize)
lastPlace = place;
lastSize = a.size;
++place;

var answer = jQuery("#answer-template").html();
answer = answer.replace("{{PLACE}}", lastPlace + ".")
.replace("{{NAME}}", a.user)
.replace("{{LANGUAGE}}", a.language)
.replace("{{SIZE}}", a.size)
.replace("{{LINK}}", a.link);
answer = jQuery(answer);
jQuery("#answers").append(answer);

var lang = a.language;
if (! /<a/.test(lang)) lang = '<i>' + lang + '</i>';
lang = jQuery(lang).text().toLowerCase();

languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link, uniq: lang};
});

var langs = [];
for (var lang in languages)
if (languages.hasOwnProperty(lang))
langs.push(languages[lang]);

langs.sort(function (a, b) {
if (a.uniq > b.uniq) return 1;
if (a.uniq < b.uniq) return -1;
return 0;
});

for (var i = 0; i < langs.length; ++i)
{
var language = jQuery("#language-template").html();
var lang = langs[i];
language = language.replace("{{LANGUAGE}}", lang.lang)
.replace("{{NAME}}", lang.user)
.replace("{{SIZE}}", lang.size)
.replace("{{LINK}}", lang.link);
language = jQuery(language);
jQuery("#languages").append(language);
}

}
body { text-align: left !important}

#answer-list {
padding: 10px;
width: 290px;
float: left;
}

#language-list {
padding: 10px;
width: 290px;
float: left;
}

table thead {
font-weight: bold;
}

table td {
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/Sites/codegolf/primary.css?v=f52df912b654">
<div id="answer-list">
<h2>Leaderboard</h2>
<table class="answer-list">
<thead>
<tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
</thead>
<tbody id="answers">

</tbody>
</table>
</div>
<div id="language-list">
<h2>Winners by Language</h2>
<table class="language-list">
<thead>
<tr><td>Language</td><td>User</td><td>Score</td></tr>
</thead>
<tbody id="languages">

</tbody>
</table>
</div>
<table style="display: none">
<tbody id="answer-template">
<tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr>
</tbody>
</table>
<table style="display: none">
<tbody id="language-template">
<tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr>
</tbody>
</table>

• (1) the score is only negative if there is any bonus. I don't think that's very relevant. (2) what's the difference between the css? May 28, 2018 at 13:54
• @user202729, now is different again. SE devs changed the stylesheet URL in meantime. That is why would be nice to have a Permaproxy to the current stylesheet. May 28, 2018 at 14:32
• Should be done now. May 31, 2018 at 5:22

Soft-linkable Leaderboard

Adding this as an answer with a single snippet in order to simply reuse the leaderboard snippet using Calvin'sHobbies' Arbitrary stack snippet loader

To use this, simply make sure that you have the snippet from the above link in your post with the configurations as below:

• site = 'meta.codegolf'
• postID = 5314
• isAnswer = true

and an additional configuration required by the leaderboard snippet:

• QUESTION_ID = id of the question for which leaderboard is required. Ex. 47338

/* Configuration */

// It will be like http://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";

/* App */

var answers = [], page = 1;

function answersUrl(index) {
return "http://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function getAnswers() {
jQuery.ajax({
url: answersUrl(page++),
method: "get",
dataType: "jsonp",
crossDomain: true,
success: function (data) {
answers.push.apply(answers, data.items);
if (data.has_more) getAnswers();
else process();
}
});
}

getAnswers();

Tie break on first posted

Ideally, if there is a joint first place I'd like to see the first posted appear at the top. This is complicated by the fact that the time of the post is not necessarily the time that the code first had that length.

I'm not suggesting the snippet do an analysis of the edit histories, but I'm posting this in case there's a simpler way. Maybe a comment override?

• Automating this definitely seems tricky, because not only would you have to figure out in the edit history when the score was first reached, but it might also happen that the score was reached before, but the answer was invalid at the time and only a later edit actually achieved the score with a valid solution. (Also, grace period...) May 25, 2016 at 10:45
• It's even worse than I thought then... So I guess the only way would be with a comment override of some kind, but unless this answer gets lots of upvotes I'm guessing that's unnecessary effort. May 25, 2016 at 10:51
• Good point about the grace period - I guess that means even a human observer can't tell for certain which was first if the edit times are within 5 minutes of each other. May 25, 2016 at 10:53