Apple Store is about to hit 25 billion downloads, and it has launched a campaign that if you download the 25 billionth app, you could win a US$10,000 App Store Gift Card. You could find more information at “iTunes 25 billion App Countdown”. This is a very interesting campaign. Apple had similar campaign for 10th billion app download last year Jan. Within short span of 1 year, apple managed to hit another 15 billion app downloads. This is really amazing.

However, I am not interested in being the lucky person who download the 25th billion app. I always knew that I cannot be this lucky. Tried TOTO a few times, but end up all donating to the government.=) The only thing that attracts me a lot is the pretty cool flashing counter that it shows on the website that keep updating the total number of app store downloads. This could not be flash as this is Apple! Without investigating on anything, I guess this could be done by Comet that constantly pushing the total downloads to the website. However, after I investigate on this, I realized that this is not true, and you may be cheated by Apple, the Number You Saw on the Website is not the Actual Download on App Store. Let’s investigate on this.
First of all, this is not flash. If you ‘Inspect Element with Firebug’, you will know that this animation is done purely using javascript. One more thing, to my surprise, apple is still using prototype!
Secondly, let’s look at how this animation is done.

Look at the screenshot of the firebug inspection on the above. You can see that the numbers on the flashing counter is from the div element ‘digitImageElement’, but there is no text of numbers in the inner HTML. You should notice there is a css rule for the background image of this div. It is an image link to http://images.apple.com/itunes/25-billion-app-countdown/images/filmstrip.png This image contains some possible frame of every numbers and the frame of transition to next number. With the top position changing in the style, it is able to change the text. This is done using the following draw function in the script download counter.js. With the help of prototype effect, the animation is pretty smooth.
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()
}
Thirdly, how the counter is incremented. This is not done by comet! It download the initial app store download counts from this link http://www.apple.com/autopush/us/itunes/includes/countdown.inc. You should see something like this in the response.
26-Feb-2012 06:00:00|24734848066|2569693
Each component is seperated by | . The first component 26-Feb-2012 06:00:00 is the last update time of the total download in GMT-0700, which is the US Mountain Time Zone time. The second component 24734848066 is the actual total apple store download count on the time 26-Feb-2012 06:00:00. The last component 2569693 means the total download in one hour, this is the rate that would be used in the javascript to calculate the speed of download in mini seconds. If you refresh the link of countdown.inc, the data is not really refreshed. I observed that this data is actually only updated every one hour.
I summary how apple is updating the download count you saw on the website in the following formula:
Total Download up to Last Hour +
(Current Time - Last Download Update Time) * (Hourly Download Count / 3600000 )
Instead of using new Date() to get the current time, it is using localServerBasedReferenceTime, which is the ‘Date’ attribute on the Response Header for the request for countdown.inc. This makes sense, as time on the user’s computer may not be correct and the time on their own server is always more trustable. So now you know that What You See on Screen is Not The Actual Download on Apple Store.
If you read the following code snippets, you will understand better all what I said
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 (localServerBasedReferenceTime) {
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();
if (this._delegate && typeof this._delegate.didLoadData === "function") {
this._delegate.didLoadData.call(this)
}
}
},
I guess when the actual download is approaching 25th billion, apple would update the countdown.inc file more often in order to make it more accurate to show the total downloads.