(function($){var useWindow=window;// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys if (!Object.keys){Object.keys=(function(){'use strict';var hasOwnProperty=Object.prototype.hasOwnProperty,hasDontEnumBug=!({toString:null}).propertyIsEnumerable('toString'),dontEnums=['toString','toLocaleString','valueOf','hasOwnProperty','isPrototypeOf','propertyIsEnumerable','constructor'],dontEnumsLength=dontEnums.length;return function(obj){if (typeof obj !=='object' && (typeof obj !=='function' || obj===null)){throw new TypeError('Object.keys called on non-object')}var result=[],prop,i;for (prop in obj){if (hasOwnProperty.call(obj,prop)){result.push(prop)}}if (hasDontEnumBug){for (i=0;i < dontEnumsLength;i++){if (hasOwnProperty.call(obj,dontEnums[i])){result.push(dontEnums[i])}}}return result}}())}// Used to disable some features on IE8 var limited_mode=false;var tick_duration=200;// in ms var debug=(location.hash==="#debug");function debug_log(msg){if (debug){console.log(msg)}}var allUnits=["Days","Hours","Minutes","Seconds"];var nextUnits={Seconds:"Minutes",Minutes:"Hours",Hours:"Days",Days:"Years"};var secondsIn={Seconds:1,Minutes:60,Hours:3600,Days:86400,Months:2678400,Years:31536000};function hexToRgb(hex){// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;hex=hex.replace(shorthandRegex,function(m,r,g,b){return r+r+g+g+b+b});var result=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);return result ?{r:parseInt(result[1],16),g:parseInt(result[2],16),b:parseInt(result[3],16)}:null}function isCanvasSupported(){var elem=document.createElement('canvas');return !!(elem.getContext && elem.getContext('2d'))}function s4(){return Math.floor((1+Math.random()) * 0x10000) .toString(16) .substring(1)}function guid(){return s4()+s4()+'-'+s4()+'-'+s4()+'-'+s4()+'-'+s4()+s4()+s4()}if (!Array.prototype.indexOf){Array.prototype.indexOf=function(elt){var len=this.length>>>0;var from=Number(arguments[1]) || 0;from=(from < 0) ? Math.ceil(from) :Math.floor(from);if (from < 0) from+=len;for (;from < len;from++){if (from in this && this[from]===elt) return from}return -1}}function parse_date(str){var match=str.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{1,2}:[0-9]{2}:[0-9]{2}$/);if (match !==null && match.length>0){var parts=str.split(" ");var date=parts[0].split("-");var time=parts[1].split(":");return new Date(date[0],date[1] - 1,date[2],time[0],time[1],time[2])}// Fallback for different date formats var d=Date.parse(str);if (!isNaN(d)) return d;d=Date.parse(str.replace(/-/g,'/').replace('T',' '));if (!isNaN(d)) return d;// Cant find anything return new Date()}function parse_times(diff,old_diff,total_duration,units,floor){var raw_time={};;;;;;var greater_unit=null;for(var i=0;i < units.length;i++){var unit=units[i];var maxUnits;if (greater_unit===null){maxUnits=total_duration / secondsIn[unit]}else{maxUnits=secondsIn[greater_unit] / secondsIn[unit]}var curUnits=(diff / secondsIn[unit]);var oldUnits=(old_diff / secondsIn[unit]);if(floor){if(curUnits>0) curUnits=Math.floor(curUnits);else curUnits=Math.ceil(curUnits);if(oldUnits>0) oldUnits=Math.floor(oldUnits);else oldUnits=Math.ceil(oldUnits)}if (unit !=="Days"){curUnits=curUnits % maxUnits;oldUnits=oldUnits % maxUnits}raw_time[unit]=curUnits;time[unit]=Math.abs(curUnits);raw_old_time[unit]=oldUnits;old_time[unit]=Math.abs(oldUnits);pct[unit]=Math.abs(curUnits) / maxUnits;old_pct[unit]=Math.abs(oldUnits) / maxUnits;greater_unit=unit}return{raw_time:raw_time,raw_old_time:raw_old_time,time:time,old_time:old_time,pct:pct,old_pct:old_pct}};function updateUsedWindow(){if(typeof useWindow.TC_Instance_List !=="undefined"){TC_Instance_List=useWindow.TC_Instance_List}else{useWindow.TC_Instance_List=TC_Instance_List}initializeAnimationFrameHandler(useWindow)};function initializeAnimationFrameHandler(w){var vendors=['webkit','moz'];for (var x=0;x < vendors.length && !w.requestAnimationFrame;++x){w.requestAnimationFrame=w[vendors[x]+'RequestAnimationFrame'];w.cancelAnimationFrame=w[vendors[x]+'CancelAnimationFrame']}if (!w.requestAnimationFrame || !w.cancelAnimationFrame){w.requestAnimationFrame=function(callback,element,instance){if (typeof instance==="undefined") instance={data:{last_frame:0}};var currTime=new Date().getTime();var timeToCall=Math.max(0, 16 - (currTime - instance.data.last_frame));var id=w.setTimeout(function(){callback(currTime+timeToCall)},timeToCall);instance.data.last_frame=currTime+timeToCall;return id};w.cancelAnimationFrame=function(id){clearTimeout(id)}}};var TC_Instance=function(element,options){this.element=element;this.container;this.listeners=null;this.data={paused:false,last_frame:0,animation_frame:null,interval_fallback:null,timer:false,total_duration:null,prev_time:null,drawn_units:[],text_elements:{Days:null,Hours:null,Minutes:null,Seconds:null},attributes:{canvas:null,context:null,item_size:null,line_width:null,radius:null,outer_radius:null},state:{fading:{Days:false,Hours:false,Minutes:false,Seconds:false}}};this.config=null;this.setOptions(options);this.initialize()};TC_Instance.prototype.clearListeners=function(){this.listeners={all:[],visible:[]}};TC_Instance.prototype.addTime=function(seconds_to_add){if(this.data.attributes.ref_date instanceof Date){var d=this.data.attributes.ref_date;d.setSeconds(d.getSeconds()+seconds_to_add)}else if(!isNaN(this.data.attributes.ref_date)){this.data.attributes.ref_date+=(seconds_to_add * 1000)}};TC_Instance.prototype.initialize=function(clear_listeners){// Initialize drawn units this.data.drawn_units=[];for(var i=0;i < Object.keys(this.config.time).length;i++){var unit=Object.keys(this.config.time)[i];if (this.config.time[unit].show){this.data.drawn_units.push(unit)}}// Avoid stacking $(this.element).children('div.time_circles').remove();if (typeof clear_listeners==="undefined") clear_listeners=true;if (clear_listeners || this.listeners===null){this.clearListeners()}this.container=$("<div>");this.container.addClass('time_circles');this.container.appendTo(this.element);// Determine the needed width and height of TimeCircles var height=this.element.offsetHeight;var width=this.element.offsetWidth;if (height===0) height=$(this.element).height();if (width===0) width=$(this.element).width();if (height===0 && width>0) height=width / this.data.drawn_units.length;else if (width===0 && height>0) width=height * this.data.drawn_units.length;// Create our canvas and set it to the appropriate size var canvasElement=document.createElement('canvas');canvasElement.width=width;canvasElement.height=height;// Add canvas elements this.data.attributes.canvas=$(canvasElement);this.data.attributes.canvas.appendTo(this.container);// Check if the browser has browser support var canvasSupported=isCanvasSupported();// If the browser doesn't have browser support, check if explorer canvas is loaded
        // (A javascript library that adds canvas support to browsers that don't have it) if(!canvasSupported && typeof G_vmlCanvasManager !=="undefined"){G_vmlCanvasManager.initElement(canvasElement);limited_mode=true;canvasSupported=true}if(canvasSupported){this.data.attributes.context=canvasElement.getContext('2d')}this.data.attributes.item_size=Math.min(width / this.data.drawn_units.length, height);this.data.attributes.line_width=this.data.attributes.item_size * this.config.fg_width;this.data.attributes.radius=((this.data.attributes.item_size * .8) - this.data.attributes.line_width) / 2;this.data.attributes.outer_radius=this.data.attributes.radius+0.5 * Math.max(this.data.attributes.line_width, this.data.attributes.line_width * this.config.bg_width);// Prepare Time Elements var i=0;for (var key in this.data.text_elements){if (!this.config.time[key].show) continue;var textElement=$("<div>");textElement.addClass('textDiv_'+key);textElement.css("top",Math.round(.35 * this.data.attributes.item_size));textElement.css("left",Math.round(i++* this.data.attributes.item_size));textElement.css("width",this.data.attributes.item_size);textElement.appendTo(this.container);var headerElement=$("<h4>");headerElement.text(this.config.time[key].text);// Options headerElement.css("font-size",Math.round(this.config.text_size * this.data.attributes.item_size));headerElement.css("line-height",Math.round(this.config.text_size * this.data.attributes.item_size)+"px");headerElement.appendTo(textElement);var numberElement=$("<span>");numberElement.css("font-size",Math.round(3 * this.config.text_size * this.data.attributes.item_size));numberElement.css("line-height",Math.round(this.config.text_size * this.data.attributes.item_size)+"px");numberElement.appendTo(textElement);this.data.text_elements[key]=numberElement}this.start();if (!this.config.start){this.data.paused=true}// Set up interval fallback var _this=this;this.data.interval_fallback=useWindow.setInterval(function(){_this.update.call(_this,true)},100)};TC_Instance.prototype.update=function(nodraw){if(typeof nodraw==="undefined"){nodraw=false}else if(nodraw && this.data.paused){return}if(limited_mode){//Per unit clearing doesn't work in IE8 using explorer canvas, so do it in one time. The downside is that radial fade cant be used
            this.data.attributes.context.clearRect(0, 0, this.data.attributes.canvas[0].width, this.data.attributes.canvas[0].hright);
        }
        var diff, old_diff;

        var prevDate = this.data.prev_time;
        var curDate = new Date();
        this.data.prev_time = curDate;

        if (prevDate === null)
            prevDate = curDate;

        // If not counting past zero, and time < 0, then simply draw the zero point once, and call stop
        if (!this.config.count_past_zero) {
            if (curDate > this.data.attributes.ref_date) {
                for(var i = 0; i < this.data.drawn_units.length; i++) {
                    var key = this.data.drawn_units[i];

                    // Set the text value
                    this.data.text_elements[key].text("0");
                    var x = (i * this.data.attributes.item_size) + (this.data.attributes.item_size / 2);
                    var y = this.data.attributes.item_size / 2;
                    var color = this.config.time[key].color;
                    this.drawArc(x, y, color, 0);
                }
                this.stop();
                return;
            }
        }

        // Compare current time with reference
        diff = (this.data.attributes.ref_date - curDate) / 1000;
        old_diff = (this.data.attributes.ref_date - prevDate) / 1000;

        var floor = this.config.animation !== "smooth";

        var visible_times = parse_times(diff, old_diff, this.data.total_duration, this.data.drawn_units, floor);
        var all_times = parse_times(diff, old_diff, secondsIn["Years"], allUnits, floor);

        var i = 0;
        var j = 0;
        var lastKey = null;

        var cur_shown = this.data.drawn_units.slice();
        for (var i in allUnits) {
            var key = allUnits[i];

            // Notify (all) listeners
            if (Math.floor(all_times.raw_time[key]) !== Math.floor(all_times.raw_old_time[key])) {
                this.notifyListeners(key, Math.floor(all_times.time[key]), Math.floor(diff), "all");
            }

            if (cur_shown.indexOf(key) < 0)
                continue;

            // Notify (visible) listeners
            if (Math.floor(visible_times.raw_time[key]) !== Math.floor(visible_times.raw_old_time[key])) {
                this.notifyListeners(key, Math.floor(visible_times.time[key]), Math.floor(diff), "visible");
            }
            
            if(!nodraw) {
                // Set the text value
                this.data.text_elements[key].text(Math.floor(Math.abs(visible_times.time[key])));

                var x = (j * this.data.attributes.item_size) + (this.data.attributes.item_size / 2);
                var y = this.data.attributes.item_size / 2;
                var color = this.config.time[key].color;

                if (this.config.animation === "smooth") {
                    if (lastKey !== null && !limited_mode) {
                        if (Math.floor(visible_times.time[lastKey]) > Math.floor(visible_times.old_time[lastKey])) {
                            this.radialFade(x, y, color, 1, key);
                            this.data.state.fading[key] = true;
                        }
                        else if (Math.floor(visible_times.time[lastKey]) < Math.floor(visible_times.old_time[lastKey])) {
                            this.radialFade(x, y, color, 0, key);
                            this.data.state.fading[key] = true;
                        }
                    }
                    if (!this.data.state.fading[key]) {
                        this.drawArc(x, y, color, visible_times.pct[key]);
                    }
                }
                else {
                    this.animateArc(x, y, color, visible_times.pct[key], visible_times.old_pct[key], (new Date()).getTime() + tick_duration);
                }
            }
            lastKey = key;
            j++;
        }

        // Dont request another update if we should be paused
        if(this.data.paused || nodraw) {
            return;
        }
        
        // We need this for our next frame either way
        var _this = this;
        var update = function() {
            _this.update.call(_this);
        };

        // Either call next update immediately, or in a second
        if (this.config.animation === "smooth") {
            // Smooth animation, Queue up the next frame
            this.data.animation_frame = useWindow.requestAnimationFrame(update, _this.element, _this);
        }
        else {
            // Tick animation, Don't queue until very slightly after the next second happens var delay=(diff % 1) * 1000;if (delay < 0) delay=1000+delay;delay+=50;_this.data.animation_frame=useWindow.setTimeout(function(){_this.data.animation_frame=useWindow.requestAnimationFrame(update,_this.element,_this)},delay)}};TC_Instance.prototype.animateArc=function(x,y,color,target_pct,cur_pct,animation_end){if (this.data.attributes.context===null) return;var diff=cur_pct - target_pct;if (Math.abs(diff)>0.5){if (target_pct===0){this.radialFade(x,y,color,1)}else{this.radialFade(x,y,color,0)}}else{var progress=(tick_duration - (animation_end - (new Date()).getTime())) / tick_duration;if (progress>1) progress=1;var pct=(cur_pct * (1 - progress))+(target_pct * progress);this.drawArc(x,y,color,pct);//var show_pct=if (progress>=1) return;var _this=this;useWindow.requestAnimationFrame(function(){_this.animateArc(x,y,color,target_pct,cur_pct,animation_end)},this.element)}};TC_Instance.prototype.drawArc=function(x,y,color,pct){if (this.data.attributes.context===null) return;var clear_radius=Math.max(this.data.attributes.outer_radius, this.data.attributes.item_size / 2);if(!limited_mode){this.data.attributes.context.clearRect(x - clear_radius,y - clear_radius,clear_radius * 2,clear_radius * 2)}if (this.config.use_background){this.data.attributes.context.beginPath();this.data.attributes.context.arc(x,y,this.data.attributes.radius,0,2 * Math.PI,false);this.data.attributes.context.lineWidth=this.data.attributes.line_width * this.config.bg_width;// line color this.data.attributes.context.strokeStyle=this.config.circle_bg_color;this.data.attributes.context.stroke()}// Direction var startAngle,endAngle,counterClockwise;var defaultOffset=(-.5 * Math.PI);var fullCircle=2 * Math.PI;startAngle=defaultOffset+(this.config.start_angle / 360 * fullCircle);var offset=(2 * pct * Math.PI);if (this.config.direction==="Both"){counterClockwise=false;startAngle -=(offset / 2);endAngle=startAngle+offset}else{if (this.config.direction==="Clockwise"){counterClockwise=false;endAngle=startAngle+offset}else{counterClockwise=true;endAngle=startAngle - offset}}this.data.attributes.context.beginPath();this.data.attributes.context.arc(x,y,this.data.attributes.radius,startAngle,endAngle,counterClockwise);this.data.attributes.context.lineWidth=this.data.attributes.line_width;// line color this.data.attributes.context.strokeStyle=color;this.data.attributes.context.stroke()};TC_Instance.prototype.radialFade=function(x,y,color,from,key){// TODO:Make fade_time option var rgb=hexToRgb(color);var _this=this;// We have a few inner scopes here that will need access to our instance var step=0.2 * ((from===1) ? -1 :1);var i;for (i=0;from <=1 && from>=0;i++){// Create inner scope so our variables are not changed by the time the Timeout triggers (function(){var delay=50 * i;var rgba="rgba("+rgb.r+", "+rgb.g+", "+rgb.b+", "+(Math.round(from * 10) / 10)+")";useWindow.setTimeout(function(){_this.drawArc(x,y,rgba,1)},delay)}());from+=step}if (typeof key !==undefined){useWindow.setTimeout(function(){_this.data.state.fading[key]=false},50 * i)}};TC_Instance.prototype.timeLeft=function(){if (this.data.paused && typeof this.data.timer==="number"){return this.data.timer}var now=new Date();return ((this.data.attributes.ref_date - now) / 1000)};TC_Instance.prototype.start=function(){useWindow.cancelAnimationFrame(this.data.animation_frame);useWindow.clearTimeout(this.data.animation_frame) // Check if a date was passed in html attribute or jquery data var attr_data_date=$(this.element).data('date');if (typeof attr_data_date==="undefined"){attr_data_date=$(this.element).attr('data-date')}if (typeof attr_data_date==="string"){this.data.attributes.ref_date=parse_date(attr_data_date)}// Check if this is an unpause of a timer else if (typeof this.data.timer==="number"){if (this.data.paused){this.data.attributes.ref_date=(new Date()).getTime()+(this.data.timer * 1000)}}else{// Try to get data-timer var attr_data_timer=$(this.element).data('timer');if (typeof attr_data_timer==="undefined"){attr_data_timer=$(this.element).attr('data-timer')}if (typeof attr_data_timer==="string"){attr_data_timer=parseFloat(attr_data_timer)}if (typeof attr_data_timer==="number"){this.data.timer=attr_data_timer;this.data.attributes.ref_date=(new Date()).getTime()+(attr_data_timer * 1000)}else{// data-timer and data-date were both not set // use config date this.data.attributes.ref_date=this.config.ref_date}}// Start running this.data.paused=false;this.update.call(this)};TC_Instance.prototype.restart=function(){this.data.timer=false;this.start()};TC_Instance.prototype.stop=function(){if (typeof this.data.timer==="number"){this.data.timer=this.timeLeft(this)}// Stop running this.data.paused=true;useWindow.cancelAnimationFrame(this.data.animation_frame)};TC_Instance.prototype.destroy=function(){this.clearListeners();this.stop();useWindow.clearInterval(this.data.interval_fallback);this.data.interval_fallback=null;this.container.remove();$(this.element).removeAttr('data-tc-id');$(this.element).removeData('tc-id')};TC_Instance.prototype.setOptions=function(options){if (this.config===null){this.default_options.ref_date=new Date();,this.default_options)}$.extend(true,this.config,options);// Use window.top if use_top_frame is true if(this.config.use_top_frame){useWindow=window.top}else{useWindow=window}updateUsedWindow();this.data.total_duration=this.config.total_duration;if (typeof this.data.total_duration==="string"){if (typeof secondsIn[this.data.total_duration] !=="undefined"){// If set to Years,Months,Days,Hours or Minutes,fetch the secondsIn value for that this.data.total_duration=secondsIn[this.data.total_duration]}else if (this.data.total_duration==="Auto"){// If set to auto,total_duration is the size of 1 unit,of the unit type bigger than the largest shown for(var i=0;i < Object.keys(this.config.time).length;i++){var unit=Object.keys(this.config.time)[i];if (this.config.time[unit].show){this.data.total_duration=secondsIn[nextUnits[unit]];break}}}else{// If it's a string, but neither of the above, user screwed up.
                this.data.total_duration = secondsIn["Years"];
                console.error("Valid values for TimeCircles config.total_duration are either numeric, or (string) Years, Months, Days, Hours, Minutes, Auto");
            }
        }
    };

    TC_Instance.prototype.addListener = function(f, context, type) {
        if (typeof f !== "function")
            return;
        if (typeof type === "undefined")
            type = "visible";
        this.listeners[type].push({func: f, scope: context});
    };

    TC_Instance.prototype.notifyListeners = function(unit, value, total, type) {
        for (var i = 0; i < this.listeners[type].length; i++) {
            var listener = this.listeners[type][i];
            listener.func.apply(listener.scope, [unit, value, total]);
        }
    };

    TC_Instance.prototype.default_options = {
        ref_date: new Date(),
        start: true,
        animation: "smooth",
        count_past_zero: true,
        circle_bg_color: "#60686F",
        use_background: true,
        fg_width: 0.1,
        bg_width: 1.2,
        text_size: 0.07,
        total_duration: "Auto",
        direction: "Clockwise",
        use_top_frame: false,
        start_angle: 0,
        time: {
            Days: {
                show: true,
                text: "Days",
                color: "#FC6"
            },
            Hours: {
                show: true,
                text: "Hours",
                color: "#9CF"
            },
            Minutes: {
                show: true,
                text: "Minutes",
                color: "#BFB"
            },
            Seconds: {
                show: true,
                text: "Seconds",
                color: "#F99"
            }
        }
    };

    // Time circle class
    var TC_Class = function(elements, options) {
        this.elements = elements;
        this.options = options;
        this.foreach();
    };

    TC_Class.prototype.getInstance = function(element) {
        var instance;

        var cur_id = $(element).data("tc-id");
        if (typeof cur_id === "undefined") {
            cur_id = guid();
            $(element).attr("data-tc-id", cur_id);
        }
        if (typeof TC_Instance_List[cur_id] === "undefined") {
            var options = this.options;
            var element_options = $(element).data('options');if (typeof element_options==="string"){element_options=JSON.parse(element_options)}if (typeof element_options==="object"){options=$.extend(true,{},this.options,element_options)}instance=new TC_Instance(element,options);TC_Instance_List[cur_id]=instance}else{instance=TC_Instance_List[cur_id];if (typeof this.options !=="undefined"){instance.setOptions(this.options)}}return instance};TC_Class.prototype.addTime=function(seconds_to_add){this.foreach(function(instance){instance.addTime(seconds_to_add)})};TC_Class.prototype.foreach=function(callback){var _this=this;this.elements.each(function(){var instance=_this.getInstance(this);if (typeof callback==="function"){callback(instance)}});return this};TC_Class.prototype.start=function(){this.foreach(function(instance){instance.start()});return this};TC_Class.prototype.stop=function(){this.foreach(function(instance){instance.stop()});return this};TC_Class.prototype.restart=function(){this.foreach(function(instance){instance.restart()});return this};TC_Class.prototype.rebuild=function(){this.foreach(function(instance){instance.initialize(false)});return this};TC_Class.prototype.getTime=function(){return this.getInstance(this.elements[0]).timeLeft()};TC_Class.prototype.addListener=function(f,type){if (typeof type==="undefined") type="visible";var _this=this;this.foreach(function(instance){instance.addListener(f,_this.elements,type)});return this};TC_Class.prototype.destroy=function(){this.foreach(function(instance){instance.destroy()});return this};TC_Class.prototype.end=function(){return this.elements};$.fn.TimeCircles=function(options){return new TC_Class(this,options)}}(jQuery));