text: (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
      };
  
      /**
       * Converts hex color code into object containing integer values for the r,g,b use
       * This function (hexToRgb) originates from:
       * http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
       * @param {string} hex color code
       */
      function hexToRgb(hex) {
  
          // Verify already RGB (e.g. "rgb(0,0,0)") or RGBA (e.g. "rgba(0,0,0,0.5)")
          var rgba = /^rgba?\(([\d]+),([\d]+),([\d]+)(,([\d\.]+))?\)$/;
          if(rgba.test(hex)) {
              var result = rgba.exec(hex);
              return {
                  r: parseInt(result[1]),
                  g: parseInt(result[2]),
                  b: parseInt(result[3]),
                  a: parseInt(result[5] ? result[5] : 1)
              };
          }
  
          // 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() and guid() originate from:
       * http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
       */
      function s4() {
          return Math.floor((1 + Math.random()) * 0x10000)
                  .toString(16)
                  .substring(1);
      }
  
      /**
       * Creates a unique id
       * @returns {String}
       */
      function guid() {
          return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
                  s4() + '-' + s4() + s4() + s4();
      }
  
      /**
       * Array.prototype.indexOf fallback for IE8
       * @param {Mixed} mixed
       * @returns {Number}
       */
      if (!Array.prototype.indexOf) {
          Array.prototype.indexOf = function(elt /*, from*/)
          {
              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 raw_old_time = {};
          var time = {};
          var pct = {};
          var old_pct = {};
          var old_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
          };
      }
  
      var TC_Instance_List = {};
      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 * 0.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(0.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.appendTo(textElement);
  
              var numberElement = $("<span>");
              numberElement.css("font-size", Math.round(this.config.number_size * this.data.attributes.item_size));
              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 = (-0.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.config = $.extend(true, {}, 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,
          number_size: 0.28,
          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));
  