31

Here; have the full, uncompressed source code for Unicoin you code monkeys!

http://dev.stackoverflow.com/content/js/stub-uc.js

This section looks pretty interesting:

var loadingVersions = {};
var powerupDeferreds = {};
function registerPowerup(id, factory, noNeedToCache) {
    var def = powerupDeferreds[id];
    var pu = factory();
    pu.id = id;
    if (pu.inherits) {
        loadPowerup(pu.inherits, abstractCacheBreakers[pu.inherits.substring(0, 4)] || "0").done(function () {
            var parent = registeredPowerups[pu.inherits];
            for (var k in parent) if (parent.hasOwnProperty(k) && !pu.hasOwnProperty(k))
                pu[k] = parent[k];
            registeredPowerups[id] = pu;
            def.resolve();
        });
    } else {
        registeredPowerups[id] = pu;
        def.resolve();
    }
    if (!noNeedToCache) {
        var val = factory.toString();
        var ver = loadingVersions[id];
        if (ver) {
            val = ver + ":" + val;
            delete loadingVersions[id];
        }
        ls_set("uc:pu" + id, val);
    }
}

function loadPowerup(id, expectedVersion) {
    var def = powerupDeferreds[id];
    if (def)
        return def;
    powerupDeferreds[id] = def = $.Deferred();
    var cached = ls_get("uc:pu" + id);
    if (cached) {
        var cachedVersion = "0";
        cached = cached.replace(/^(\w+):/, function (whole, ver) { cachedVersion = ver; return "" });
        if (cachedVersion === expectedVersion) {
            // indirect call so we don't inerit this scope (at least in modern browsers)
            registerPowerup(id, eval.call(window, ("(" + cached + ")")), true);
            return def;
        }
    }
    if (expectedVersion !== "0")
        loadingVersions[id] = expectedVersion;
    StackExchange.loadJsFile("unicoin/powerups/" + id + ".js?v=" + expectedVersion, /* doNotLocalize=*/true);
    return def;
}

function loadAndRunPowerup(id, option) {
    var def = $.Deferred();
    var version = "0";
    id = id.replace(/\?(\w*)$/, function (whole, ver) { version = ver; return "" });
    loadPowerup(id, version).done(function () {
        var pu = registeredPowerups[id];
        if (pu.setOption)
            pu.setOption(option);
        pu.enable();
        pu.enabled = true;
        def.resolve(pu);
    });
    return def.promise();
}

function loadAndRunPowerups(powerups) {
    for (var i = 0; i< powerups.length; i++) {
        loadAndRunPowerup.apply(null, powerups[i]);
    }
}

I think the key here is

StackExchange.loadJsFile("unicoin/powerups/" + id + ".js?v=" + expectedVersion, /* doNotLocalize=*/true);

If I'm right and we can figure out what the ids are, then

  • We can illicitly gain powerups without buying them!
  • We can save the powerup source code and use them even after April Fools' Day is over!
    • This means that UNICORN VOTING ANIMATIONS CAN BE HERE FOREVAR!!!

So what are you waiting for, all you JS coders? Help me hack Unicoin so it can be here forever!

closed as off-topic by kiamlaluno, Azik, Shog9 Apr 4 '14 at 19:14

This question appears to be off-topic. The users who voted to close gave these specific reasons:

  • "This question was asked in regards to the 2014 April Fools feature, "Unicoins". Since it is no longer April 1st, Unicoins are now considered off-topic." – Shog9
  • "The problem described here can no longer be reproduced. Changes to the system or to the circumstances affecting the asker have rendered it obsolete. If you encounter a similar problem, please post a new question." – kiamlaluno, Azik
If this question can be reworded to fit the rules in the help center, please edit the question.

  • That deferred anti pattern hurts my eyes :( Seriously - what's wrong with return loadPowerUp(id,version).then(function(){ ... })? What's the point of using deferred objects and promises if you're not using them correctly and are using them as callbacks? – Benjamin Gruenbaum Apr 1 '14 at 21:10
  • 5
    Why don't you just look at the source code? That's what the developers where I work do. – Nick Craver Apr 1 '14 at 21:37
  • @NickCraver I tried. (And I finally succeeded; see my answer below :D) – Doorknob Apr 1 '14 at 21:37
  • Apologies for extreme n00bishness, but why can't you just add // ==UserScript== // @name [Name here] // @namespace [stuff here] // @description [stuff here] // @include [ALL TEH SITEZ] // @version [number here] // @grant [stuff here] // ==/UserScript== to the top of stub-uc.js and call it a UserScript? – The Guy with The Hat Apr 1 '14 at 22:01
  • 2
    This question appears to be off-topic because it is about programming. :-P – mhlester Apr 2 '14 at 4:22
  • @TheGuywithTheHat Unicorn Voting 2014 Chrome user script extension. – Jason Sturges Apr 2 '14 at 5:40
  • @JasonSturges ...isn't that exactly the same thing as what I posted on Stack Apps? Why are you spamming that all over my posts? – Doorknob Apr 2 '14 at 12:10
  • 1
    @Doorknob It's wrapped to enable Google Chrome extension - your user script as is didn't work. – Jason Sturges Apr 2 '14 at 14:25
20

UPDATE: Yes! Victory for reverse-engineering of the unicorn voting animations!

UPDATE 2: I made a userscript! Find it here on Stack Apps!

Here I shall document my progress so far.

This URL: http://meta.stackoverflow.com/unicoin/available-powerups looks promising....

{"powerups":[{"name":"Voting animations","useid":"f1bb643faf2c4382a56a7dfb945269c8","purchaseid":"9612a9430ef7ef2f6b3a064a83260996","cost":99,"owned":true,"description":"Happy unicorn animations every time you vote. You know you want it."},{"name":"No downvotes, please","useid":"b4519d83340a4064adc84e0fe0913b14","purchaseid":"53446efe7a8a25df46c27dda89fa22f5","cost":80,"owned":true,"description":"Remove the downvote arrows from all your questions and answers."},{"name":"Bobblehead","useid":"de274e4442324c499defc115544c2983","purchaseid":"79391fd64d184dd224ac79d0a01d02e4","cost":75,"owned":true,"description":"All the users too stiff for your taste? You can change that!"},{"name":"Colorful comments","useid":"a91005683eaa4617834345d09fda1399","purchaseid":"8cef362f3bf6cbf54bd009be5baf4c93","cost":30,"owned":true,"description":"Make comments more interesting by giving them personality."},{"name":"No sidebar widget","purchaseid":"eec5b866ea0da6041ae33e88ffcdab64","cost":20,"owned":false,"description":"Access Unicoins through the link in the footer instead."},{"name":"Cut everyone's rep","purchaseid":"734257255700bda6d877c1bf888f45e7","cost":45,"owned":false,"description":"Divide everybody's reputation (except your own) by ten."},{"name":"Adopt-a-tag","purchaseid":"f29f250e83fb902cb58dba7a5c7d61c0","cost":50,"owned":false,"description":"Choose a tag and have your own avatar appear on it everywhere."},{"name":"Guaranteed answer","purchaseid":"b656db0c5c4ab9a4a39cb916de2a63b8","cost":50,"owned":false,"description":"No more need to wait: We guarantee you an answer on all of your questions."},{"name":"Marquee","purchaseid":"f50d472beed81e0160dbf60bd1a15cd9","cost":55,"owned":false,"description":"Make question titles livelier by scrolling them like a ticker."},{"name":"Because unicorns","purchaseid":"aeac6a6e7d86cae21a4d925daf5a9fb1","cost":60,"owned":false,"description":"\"Closed because unicorns\" is the only valid close reason."},{"name":"Purple Q&A","purchaseid":"e352e537edd73af633e987f9300208f2","cost":65,"owned":false,"description":"Make your posts stand out with a distinguished shade of purple."},{"name":"Top bar color chooser","purchaseid":"22a2577a4838be35438146d5d05e7b4b","cost":80,"owned":false,"description":"Dark gray too boring for you? Customize your top bar's color scheme."},{"name":"Reputation to the max","purchaseid":"b9e0a8c95e4feedf11a882fcb47561e0","cost":90,"owned":false,"description":"Increase your own reputation by a settable factor."}]}

Yes yes yes! When I go to http://meta.stackoverflow.com/content/js/unicoin/powerups/f1bb643faf2c4382a56a7dfb945269c8.js, I see this:

StackExchange.uc.registerPowerup("f1bb643faf2c4382a56a7dfb945269c8",function(){return{"enable":function(){function e(e){var t=$.Deferred(),n=$("<img />").attr("src",p+e).css({"position":"fixed","top":0,"left":0,"width":1,"height":1}).appendTo("body");if(n[0].complete)n.remove(),t.resolve();else{var i=!1;n.bind("load readystatechange",function a(e){(this.complete||"complete"==this.readyState&&"readystatechange"==e.type)&&(i||(i=!0,n.unbind("load readystatechange",a),n.remove(),t.resolve()))})}return t.promise()}function t(e,t,n,i,a,o){var s=$("<div />").css({"width":i,"height":a,"backgroundImage":"url("+p+e+")","position":"absolute","top":n,"left":t,"display":"none"}).appendTo("body");return o||s.fadeIn(),s.set=function(e){this.css("background-position","0px "+-a*e+"px")},s.finish=function(e){this.fadeOut(function(){$(this).remove(),e&&e()})},s}function n(n){var i="1Fba1.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-100,e.top-40,151,100),o=0,s=setInterval(function(){a.set(o++),11==o&&n.css({"position":"relative"}).animate({"left":400,"top":-100},1e3,"linear").animate({"left":600,"top":50},500,"linear").animate({"left":0,"top":0},1500,"linear",function(){d=!1}),20==o&&(clearInterval(s),a.finish())},150)},o=e(i);return o.run=a,o}function i(n){var i="1XY5D.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-100,e.top-50,172,100),o=0,s=setInterval(function(){a.set(o++),20==o&&(clearInterval(s),a.finish(function(){d=!1}))},100)},o=e(i);return o.run=a,o}function a(n){var i="cMyYU.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left,e.top+50,80,120),o=0,s=setInterval(function(){a.set(o++),20==o&&(clearInterval(s),setTimeout(function(){a.finish(function(){d=!1})},2e3))},100)},o=e(i);return o.run=a,o}function o(n){var i="4q8j8.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-60,e.top-80,120,101),o=0,s=setInterval(function(){a.set(o++),a.css("left",e.left-60-o),20==o&&(clearInterval(s),setTimeout(function(){a.finish(function(){d=!1})},2e3))},100)},o=e(i);return o.run=a,o}function s(n){var i="cBop8.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-50,e.top-20,125,150),o=0,s=setInterval(function(){o++;var e=o%18;e>9&&(e=17-e),a.set(e),40==o&&(clearInterval(s),a.finish(function(){d=!1}))},100)},o=e(i);return o.run=a,o}function r(n){var i="tjvfW.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-130,e.top-20,120,117),o=0,s=setInterval(function(){o++;var e=o%29;e>14&&(e=29-e),a.set(e),80==o&&(clearInterval(s),a.finish(function(){d=!1}))},100)},o=e(i);return o.run=a,o}function c(n){var i="lyX66.png",a=parseInt(n.css("font-size")),o=function(){d=!0;var e=n.offset(),o=t(i,e.left-80,e.top-40,120,109),s=0,r=setInterval(function(){s++;var e=s-3;e>19&&(e=18-(e-20)%8,15>e&&(e=30-e)),13==s&&n.animate({"fontSize":0}),o.set(Math.max(0,e)),40==s&&(clearInterval(r),n.animate({"font-size":a},1e3),o.finish(function(){d=!1}))},150)},s=e(i);return s.run=o,s}function l(n){var i="xBS3c.png",a=function(){d=!0,n.css({"position":"relative"});var e=n.offset(),a=$(window).width()-140,o=t(i,a,e.top-20,140,102),s=0,r=setInterval(function(){s++,a-=20,a<e.left+30&&n.css("left",a-e.left-30),o.set(s%15),o.css("left",a),-140>a&&(clearInterval(r),setTimeout(function(){n.hide().css("left",0).fadeIn("slow")},2e3),o.finish(function(){d=!1}))},50)},o=e(i);return o.run=a,o}function u(n){var i="RXgxY.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left+300,e.top-130,100,114),o=0,s=setInterval(function(){a.set(o++),18==o&&(horn=t(i,e.left+290,e.top-40,15,12,!0),horn.set(159),horn.show().animate({"left":e.left+30,"top":e.top+15},700,"linear")),20==o&&(clearInterval(s),setTimeout(function(){a.finish(),horn.finish(function(){d=!1})},2e3))},100)},o=e(i);return o.run=a,o}var d=!1,p="//i.stack.imgur.com/";window.evaluator=function(e,t){if(d)return null;var p,f=[o,r,a,i],h=[c,l,u,s,n],g=t?f:h;return p=g[Math.floor(Math.random()*g.length)](e),p&&!p.cancel&&(p.cancel=function(){}),p}},"disable":function(){delete window.evaluator}}});

More reverse-engineering is needed.... >:O

So here's the functions for unicorn animations when voting....

function n(n){var i="1Fba1.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-100,e.top-40,151,100),o=0,s=setInterval(function(){a.set(o++),11==o&&n.css({"position":"relative"}).animate({"left":400,"top":-100},1e3,"linear").animate({"left":600,"top":50},500,"linear").animate({"left":0,"top":0},1500,"linear",function(){d=!1}),20==o&&(clearInterval(s),a.finish())},150)},o=e(i);return o.run=a,o}function i(n){var i="1XY5D.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-100,e.top-50,172,100),o=0,s=setInterval(function(){a.set(o++),20==o&&(clearInterval(s),a.finish(function(){d=!1}))},100)},o=e(i);return o.run=a,o}function a(n){var i="cMyYU.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left,e.top+50,80,120),o=0,s=setInterval(function(){a.set(o++),20==o&&(clearInterval(s),setTimeout(function(){a.finish(function(){d=!1})},2e3))},100)},o=e(i);return o.run=a,o}function o(n){var i="4q8j8.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-60,e.top-80,120,101),o=0,s=setInterval(function(){a.set(o++),a.css("left",e.left-60-o),20==o&&(clearInterval(s),setTimeout(function(){a.finish(function(){d=!1})},2e3))},100)},o=e(i);return o.run=a,o}function s(n){var i="cBop8.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-50,e.top-20,125,150),o=0,s=setInterval(function(){o++;var e=o%18;e>9&&(e=17-e),a.set(e),40==o&&(clearInterval(s),a.finish(function(){d=!1}))},100)},o=e(i);return o.run=a,o}function r(n){var i="tjvfW.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left-130,e.top-20,120,117),o=0,s=setInterval(function(){o++;var e=o%29;e>14&&(e=29-e),a.set(e),80==o&&(clearInterval(s),a.finish(function(){d=!1}))},100)},o=e(i);return o.run=a,o}function c(n){var i="lyX66.png",a=parseInt(n.css("font-size")),o=function(){d=!0;var e=n.offset(),o=t(i,e.left-80,e.top-40,120,109),s=0,r=setInterval(function(){s++;var e=s-3;e>19&&(e=18-(e-20)%8,15>e&&(e=30-e)),13==s&&n.animate({"fontSize":0}),o.set(Math.max(0,e)),40==s&&(clearInterval(r),n.animate({"font-size":a},1e3),o.finish(function(){d=!1}))},150)},s=e(i);return s.run=o,s}function l(n){var i="xBS3c.png",a=function(){d=!0,n.css({"position":"relative"});var e=n.offset(),a=$(window).width()-140,o=t(i,a,e.top-20,140,102),s=0,r=setInterval(function(){s++,a-=20,a<e.left+30&&n.css("left",a-e.left-30),o.set(s%15),o.css("left",a),-140>a&&(clearInterval(r),setTimeout(function(){n.hide().css("left",0).fadeIn("slow")},2e3),o.finish(function(){d=!1}))},50)},o=e(i);return o.run=a,o}function u(n){var i="RXgxY.png",a=function(){d=!0;var e=n.offset(),a=t(i,e.left+300,e.top-130,100,114),o=0,s=setInterval(function(){a.set(o++),18==o&&(horn=t(i,e.left+290,e.top-40,15,12,!0),horn.set(159),horn.show().animate({"left":e.left+30,"top":e.top+15},700,"linear")),20==o&&(clearInterval(s),setTimeout(function(){a.finish(),horn.finish(function(){d=!1})},2e3))},100)},o=e(i);return o.run=a,o}

And the main function used for all of them:

function t(e,t,n,i,a,o){var s=$("<div />").css({"width":i,"height":a,"backgroundImage":"url("+p+e+")","position":"absolute","top":n,"left":t,"display":"none"}).appendTo("body");return o||s.fadeIn(),s.set=function(e){this.css("background-position","0px "+-a*e+"px")},s.finish=function(e){this.fadeOut(function(){$(this).remove(),e&&e()})},s}

Let's beautify that:

function t(e, t, n, i, a, o) {
    var s = $("<div />").css({
        "width": i,
        "height": a,
        "backgroundImage": "url(" + p + e + ")",
        "position": "absolute",
        "top": n,
        "left": t,
        "display": "none"
    }).appendTo("body");
    return o || s.fadeIn(), s.set = function (e) {
        this.css("background-position", "0px " + -a * e + "px")
    }, s.finish = function (e) {
        this.fadeOut(function () {
            $(this).remove(), e && e()
        })
    }, s
}

function n(n) {
    var i = "1Fba1.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left - 100, e.top - 40, 151, 100),
                o = 0,
                s = setInterval(function () {
                    a.set(o++), 11 == o && n.css({
                        "position": "relative"
                    }).animate({
                        "left": 400,
                        "top": -100
                    }, 1e3, "linear").animate({
                        "left": 600,
                        "top": 50
                    }, 500, "linear").animate({
                        "left": 0,
                        "top": 0
                    }, 1500, "linear", function () {
                        d = !1
                    }), 20 == o && (clearInterval(s), a.finish())
                }, 150)
        }, o = e(i);
    return o.run = a, o
}

function i(n) {
    var i = "1XY5D.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left - 100, e.top - 50, 172, 100),
                o = 0,
                s = setInterval(function () {
                    a.set(o++), 20 == o && (clearInterval(s), a.finish(function () {
                        d = !1
                    }))
                }, 100)
        }, o = e(i);
    return o.run = a, o
}

function a(n) {
    var i = "cMyYU.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left, e.top + 50, 80, 120),
                o = 0,
                s = setInterval(function () {
                    a.set(o++), 20 == o && (clearInterval(s), setTimeout(function () {
                        a.finish(function () {
                            d = !1
                        })
                    }, 2e3))
                }, 100)
        }, o = e(i);
    return o.run = a, o
}

function o(n) {
    var i = "4q8j8.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left - 60, e.top - 80, 120, 101),
                o = 0,
                s = setInterval(function () {
                    a.set(o++), a.css("left", e.left - 60 - o), 20 == o && (clearInterval(s), setTimeout(function () {
                        a.finish(function () {
                            d = !1
                        })
                    }, 2e3))
                }, 100)
        }, o = e(i);
    return o.run = a, o
}

function s(n) {
    var i = "cBop8.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left - 50, e.top - 20, 125, 150),
                o = 0,
                s = setInterval(function () {
                    o++;
                    var e = o % 18;
                    e > 9 && (e = 17 - e), a.set(e), 40 == o && (clearInterval(s), a.finish(function () {
                        d = !1
                    }))
                }, 100)
        }, o = e(i);
    return o.run = a, o
}

function r(n) {
    var i = "tjvfW.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left - 130, e.top - 20, 120, 117),
                o = 0,
                s = setInterval(function () {
                    o++;
                    var e = o % 29;
                    e > 14 && (e = 29 - e), a.set(e), 80 == o && (clearInterval(s), a.finish(function () {
                        d = !1
                    }))
                }, 100)
        }, o = e(i);
    return o.run = a, o
}

function c(n) {
    var i = "lyX66.png",
        a = parseInt(n.css("font-size")),
        o = function () {
            d = !0;
            var e = n.offset(),
                o = t(i, e.left - 80, e.top - 40, 120, 109),
                s = 0,
                r = setInterval(function () {
                    s++;
                    var e = s - 3;
                    e > 19 && (e = 18 - (e - 20) % 8, 15 > e && (e = 30 - e)), 13 == s && n.animate({
                        "fontSize": 0
                    }), o.set(Math.max(0, e)), 40 == s && (clearInterval(r), n.animate({
                        "font-size": a
                    }, 1e3), o.finish(function () {
                        d = !1
                    }))
                }, 150)
        }, s = e(i);
    return s.run = o, s
}

function l(n) {
    var i = "xBS3c.png",
        a = function () {
            d = !0, n.css({
                "position": "relative"
            });
            var e = n.offset(),
                a = $(window).width() - 140,
                o = t(i, a, e.top - 20, 140, 102),
                s = 0,
                r = setInterval(function () {
                    s++, a -= 20, a < e.left + 30 && n.css("left", a - e.left - 30), o.set(s % 15), o.css("left", a), -140 > a && (clearInterval(r), setTimeout(function () {
                        n.hide().css("left", 0).fadeIn("slow")
                    }, 2e3), o.finish(function () {
                        d = !1
                    }))
                }, 50)
        }, o = e(i);
    return o.run = a, o
}

function u(n) {
    var i = "RXgxY.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left + 300, e.top - 130, 100, 114),
                o = 0,
                s = setInterval(function () {
                    a.set(o++), 18 == o && (horn = t(i, e.left + 290, e.top - 40, 15, 12, !0), horn.set(159), horn.show().animate({
                        "left": e.left + 30,
                        "top": e.top + 15
                    }, 700, "linear")), 20 == o && (clearInterval(s), setTimeout(function () {
                        a.finish(), horn.finish(function () {
                            d = !1
                        })
                    }, 2e3))
                }, 100)
        }, o = e(i);
    return o.run = a, o
}

And I've done it! :D Run this code on this page and watch the vote button area on my question.

var p = "http://i.stack.imgur.com/"

function t(e, t, n, i, a, o) {
    var s = $("<div />").css({
        "width": i,
        "height": a,
        "backgroundImage": "url(" + p + e + ")",
        "position": "absolute",
        "top": n,
        "left": t,
        "display": "none"
    }).appendTo("body");
    return o || s.fadeIn(), s.set = function (e) {
        this.css("background-position", "0px " + -a * e + "px")
    }, s.finish = function (e) {
        this.fadeOut(function () {
            $(this).remove(), e && e()
        })
    }, s
}

function n(n) {
    var i = "1Fba1.png",
        a = function () {
            d = !0;
            var e = n.offset(),
                a = t(i, e.left - 100, e.top - 40, 151, 100),
                o = 0,
                s = setInterval(function () {
                    a.set(o++), 11 == o && n.css({
                        "position": "relative"
                    }).animate({
                        "left": 400,
                        "top": -100
                    }, 1e3, "linear").animate({
                        "left": 600,
                        "top": 50
                    }, 500, "linear").animate({
                        "left": 0,
                        "top": 0
                    }, 1500, "linear", function () {
                        d = !1
                    }), 20 == o && (clearInterval(s), a.finish())
                }, 150)
        }
    a()
}

n($('.vote-count-post:first'))

Now it's time for a userscript!

Not the answer you're looking for? Browse other questions tagged .