+
+var upload_time_estimation_total_size = 42;
+var upload_time_estimation_transfered_size = 42;
+var upload_time_estimation_transfered_date = 42;
+var upload_time_estimation_moving_average_speed = 42;
+
+function upload_time_estimation_init(total_size)
+{
+    upload_time_estimation_total_size = total_size;
+    upload_time_estimation_transfered_size = 0;
+    upload_time_estimation_moving_average_speed = 0;
+    var d = new Date();
+    upload_time_estimation_transfered_date = d.getMilliseconds();
+}
+
+function upload_time_estimation_add(total_transfered_size)
+{
+    // Let's compute the current speed
+    var d = new Date();
+    var speed = upload_time_estimation_moving_average_speed;
+    if (d.getMilliseconds() - upload_time_estimation_transfered_date != 0)
+        speed = (total_transfered_size - upload_time_estimation_transfered_size)
+                / (d.getMilliseconds() - upload_time_estimation_transfered_date);
+    // Let's compute moving average speed on 30 values
+    var m = (upload_time_estimation_moving_average_speed * 29 + speed) / 30;
+    // Update global values
+    upload_time_estimation_transfered_size = total_transfered_size;
+    upload_time_estimation_transfered_date = d.getMilliseconds();
+    upload_time_estimation_moving_average_speed = m;
+}
+
+function upload_time_estimation_speed_string()
+{
+    // speed ms -> s
+    var s = upload_time_estimation_moving_average_speed * 1000;
+    var res = 0;
+    var scale = '';
+    if (s <= 1000)
+    {
+        res = s.toString();
+        scale = "o/s";
+    }
+    else if (s < 1000000)
+    {
+        res = Math.floor(s/1000) + ((Math.floor(s/100) - (Math.floor(s/1000) * 10)) / 10);
+        scale = "Ko/s";
+    }
+    else
+    {
+        res = Math.floor(s/1000000) + ((Math.floor(s/100000) - (Math.floor(s/1000000) * 10)) / 10);
+        scale = "Mo/s";
+    }
+    if (res == 0)
+        return '';
+    else
+        return res.toString() + ' ' + scale;
+}
+
+function milliseconds_to_date_string (milliseconds)
+{
+    function numberEnding (number) {
+        return (number > 1) ? 's' : '';
+    }
+
+    var temp = Math.floor(milliseconds / 1000);
+    var years = Math.floor(temp / 31536000);
+    if (years) {
+        return years + ' year' + numberEnding(years);
+    }
+    var days = Math.floor((temp %= 31536000) / 86400);
+    if (days) {
+        return days + ' day' + numberEnding(days);
+    }
+    var hours = Math.floor((temp %= 86400) / 3600);
+    if (hours) {
+        return hours + ' hour' + numberEnding(hours);
+    }
+    var minutes = Math.floor((temp %= 3600) / 60);
+    if (minutes) {
+        return minutes + ' minute' + numberEnding(minutes);
+    }
+    var seconds = temp % 60;
+    if (seconds) {
+        return seconds + ' second' + numberEnding(seconds);
+    }
+    return 'less than a second';
+}
+
+function upload_time_estimation_time_string()
+{
+    // Estimate remaining time
+    var t = (upload_time_estimation_total_size - upload_time_estimation_transfered_size)
+            / upload_time_estimation_moving_average_speed;
+    if (t == -1)
+        return ''
+    else
+        return milliseconds_to_date_string (t);
+}
+