text: /*****
   * rateyo - v2.3.5
   * http://prrashi.github.io/rateyo/
   * Copyright (c) 2014 Prashanth Pamidi; Licensed MIT
   *****/
  
  ;
  (function($) {
      "use strict";
  
      // The basic svg string required to generate stars
      var BASICSTAR = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
          "<svg version=\"1.1\"" +
          "xmlns=\"http://www.w3.org/2000/svg\"" +
          "viewBox=\"0 12.705 512 486.59\"" +
          "x=\"0px\" y=\"0px\"" +
          "xml:space=\"preserve\">" +
          "<polygon " +
          "points=\"256.814,12.705 317.205,198.566" +
          " 512.631,198.566 354.529,313.435 " +
          "414.918,499.295 256.814,384.427 " +
          "98.713,499.295 159.102,313.435 " +
          "1,198.566 196.426,198.566 \"/>" +
          "</svg>";
  
      // The Default values of different options available in the Plugin
      var DEFAULTS = {
  
          starWidth: "32px",
          normalFill: "gray",
          ratedFill: "#f39c12",
          numStars: 5,
          maxValue: 5,
          precision: 1,
          rating: 0,
          fullStar: false,
          halfStar: false,
          readOnly: false,
          spacing: "0px",
          rtl: false,
          multiColor: null,
          onInit: null,
          onChange: null,
          onSet: null,
          starSvg: null
      };
  
      //Default colors for multi-color rating
      var MULTICOLOR_OPTIONS = {
  
          startColor: "#c0392b", //red
          endColor: "#f1c40f" //yellow
      };
  
      // http://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
      function isMobileBrowser() {
          var check = false;
          /* jshint ignore:start */
          (function(a) { if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true })(navigator.userAgent || navigator.vendor || window.opera);
          /* jshint ignore:end */
          return check;
      }
  
      function checkPrecision(value, minValue, maxValue) {
  
          /*
           * This function removes the unnecessary precision, at Min and Max Values
           */
  
          // Its like comparing 0.0 with 0, which is true
          if (value === minValue) {
  
              value = minValue;
          } else if (value === maxValue) {
  
              value = maxValue;
          }
  
          return value;
      }
  
      function checkBounds(value, minValue, maxValue) {
  
          /*
           * Check if the value is between min and max values, if not, throw an error
           */
  
          var isValid = value >= minValue && value <= maxValue;
  
          if (!isValid) {
  
              throw Error("Invalid Rating, expected value between " + minValue +
                  " and " + maxValue);
          }
  
          return value;
      }
  
      function isDefined(value) {
  
          // Better way to check if a variable is defined or not
          return typeof value !== "undefined";
      }
  
      // Regex to match Colors in Hex Format like #FF00FF
      var hexRegex = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
  
      var hexToRGB = function(hex) {
  
          /*
           * Extracts and returns the Red, Blue, Green Channel values,
           * in the form of decimals
           */
  
          if (!hexRegex.test(hex)) {
  
              return null;
          }
  
          var hexValues = hexRegex.exec(hex),
              r = parseInt(hexValues[1], 16),
              g = parseInt(hexValues[2], 16),
              b = parseInt(hexValues[3], 16);
  
          return { r: r, g: g, b: b };
      };
  
      function getChannelValue(startVal, endVal, percent) {
  
          /*
           * Returns a value between `startVal` and `endVal` based on the percent
           */
  
          var newVal = (endVal - startVal) * (percent / 100);
  
          newVal = Math.round(startVal + newVal).toString(16);
  
          if (newVal.length === 1) {
  
              newVal = "0" + newVal;
          }
  
          return newVal;
      }
  
      function getColor(startColor, endColor, percent) {
  
          /*
           * Given the percentage( `percent` ) of `endColor` to be mixed
           * with the `startColor`, returns the mixed color.
           * Colors should be only in Hex Format
           */
  
          if (!startColor || !endColor) {
  
              return null;
          }
  
          percent = isDefined(percent) ? percent : 0;
  
          startColor = hexToRGB(startColor);
          endColor = hexToRGB(endColor);
  
          var r = getChannelValue(startColor.r, endColor.r, percent),
              b = getChannelValue(startColor.b, endColor.b, percent),
              g = getChannelValue(startColor.g, endColor.g, percent);
  
          return "#" + r + g + b;
      }
  
      function RateYo($node, options) {
  
          /*
           * The Contructor, whose instances are used by plugin itself
           */
  
          // Storing the HTML element as a property, for future access
          this.node = $node.get(0);
  
          var that = this;
  
          // Remove any stuff that is present inside the container, and add the plugin class
          $node.empty().addClass("jq-ry-container");
  
          /*
           * Basically the plugin displays the rating using two rows of stars lying one above
           * the other, the row that is on the top represents the actual rating, and the one
           * behind acts just like a background.
           *
           * `$groupWrapper`: is an element that wraps both the rows
           * `$normalGroup`: is the container for row of stars thats behind and
           *                 acts as background
           * `$ratedGroup`: is the container for row of stars that display the actual rating.
           *
           * The rating is displayed by adjusting the width of `$ratedGroup`
           */
          var $groupWrapper = $("<div/>").addClass("jq-ry-group-wrapper")
              .appendTo($node);
  
          var $normalGroup = $("<div/>").addClass("jq-ry-normal-group")
              .addClass("jq-ry-group")
              .appendTo($groupWrapper);
  
          var $ratedGroup = $("<div/>").addClass("jq-ry-rated-group")
              .addClass("jq-ry-group")
              .appendTo($groupWrapper);
  
          /*
           * Variable `step`: store the value of the rating for each star
           *                  eg: if `maxValue` is 5 and `numStars` is 5, value of each star
           *                      is 1.
           * Variable `starWidth`: stores the decimal value of width of star in units of px
           * Variable `percentOfStar`: stores the percentage of width each star takes w.r.t
           *                           the container
           * Variable `spacing`: stores the decimal value of the spacing between stars
           *                     in the units of px
           * Variable `percentOfSpacing`: stores the percentage of width of the spacing
           *                              between stars w.r.t the container
           */
          var step, starWidth, percentOfStar, spacing,
              percentOfSpacing, containerWidth, minValue = 0;
  
          /*
           * `currentRating` contains rating that is being displayed at the latest point of
           * time.
           *
           * When ever you hover over the plugin UI, the rating value changes
           * according to the place where you point the cursor, currentRating contains
           * the current value of rating that is being shown in the UI
           */
          var currentRating = options.rating;
  
          // A flag to store if the plugin is already being displayed in the UI
          var isInitialized = false;
  
          function showRating(ratingVal) {
  
              /*
               * The function is responsible for displaying the rating by changing
               * the width of `$ratedGroup`
               */
  
              if (!isDefined(ratingVal)) {
  
                  ratingVal = options.rating;
              }
  
              // Storing the value that is being shown in `currentRating`.
              currentRating = ratingVal;
  
              var numStarsToShow = ratingVal / step;
  
              // calculating the percentage of width of $ratedGroup with respect to its parent
              var percent = numStarsToShow * percentOfStar;
  
              if (numStarsToShow > 1) {
  
                  // adding the percentage of space that is taken by the gap the stars
                  percent += (Math.ceil(numStarsToShow) - 1) * percentOfSpacing;
              }
  
              setRatedFill(options.ratedFill);
  
              percent = options.rtl ? 100 - percent : percent;
  
              if (percent < 0) {
  
                  percent = 0;
              } else if (percent > 100) {
  
                  percent = 100;
              }
  
              $ratedGroup.css("width", percent + "%");
          }
  
          function setContainerWidth() {
  
              /*
               * Set the width of the `this.node` based on the width of each star and
               * the space between them
               */
  
              containerWidth = starWidth * options.numStars + spacing * (options.numStars - 1);
  
              percentOfStar = (starWidth / containerWidth) * 100;
  
              percentOfSpacing = (spacing / containerWidth) * 100;
  
              $node.width(containerWidth);
  
              showRating();
          }
  
          function setStarWidth(newWidth) {
  
              /*
               * Set the width and height of each SVG star, called whenever one changes the
               * `starWidth` option
               */
  
              // The width and height of the star should be the same
              var starHeight = options.starWidth = newWidth;
  
              starWidth = window.parseFloat(options.starWidth.replace("px", ""));
  
              $normalGroup.find("svg")
                  .attr({
                      width: options.starWidth,
                      height: starHeight
                  });
  
              $ratedGroup.find("svg")
                  .attr({
                      width: options.starWidth,
                      height: starHeight
                  });
  
              setContainerWidth();
  
              return $node;
          }
  
          function setSpacing(newSpacing) {
  
              /*
               * Set spacing between the SVG stars, called whenever one changes
               * the `spacing` option
               */
  
              options.spacing = newSpacing;
  
              spacing = parseFloat(options.spacing.replace("px", ""));
  
              $normalGroup.find("svg:not(:first-child)")
                  .css({ "margin-left": newSpacing });
  
              $ratedGroup.find("svg:not(:first-child)")
                  .css({ "margin-left": newSpacing });
  
              setContainerWidth();
  
              return $node;
          }
  
          function setNormalFill(newFill) {
  
              /*
               * Set the background fill of the Stars, called whenever one changes the
               * `normalFill` option
               */
  
              options.normalFill = newFill;
  
              var $svgs = (options.rtl ? $ratedGroup : $normalGroup).find("svg");
  
              $svgs.attr({ fill: options.normalFill });
  
              return $node;
          }
  
          /*
           * Store the recent `ratedFill` option in a variable
           * so that if multiColor is unset, we can use the perviously set `ratedFill`
           * from this variable
           */
          var ratedFill = options.ratedFill;
  
          function setRatedFill(newFill) {
  
              /*
               * Set ratedFill of the stars, called when one changes the `ratedFill` option
               */
  
              /*
               * If `multiColor` option is set, `newFill` variable is dynamically set
               * based on the rating, what ever set as parameter will be discarded
               */
              if (options.multiColor) {
  
                  var ratingDiff = currentRating - minValue,
                      percentCovered = (ratingDiff / options.maxValue) * 100;
  
                  var colorOpts = options.multiColor || {},
                      startColor = colorOpts.startColor || MULTICOLOR_OPTIONS.startColor,
                      endColor = colorOpts.endColor || MULTICOLOR_OPTIONS.endColor;
  
                  newFill = getColor(startColor, endColor, percentCovered);
              } else {
  
                  ratedFill = newFill;
              }
  
              options.ratedFill = newFill;
  
              var $svgs = (options.rtl ? $normalGroup : $ratedGroup).find("svg");
  
              $svgs.attr({ fill: options.ratedFill });
  
              return $node;
          }
  
          function setRtl(newValue) {
  
              newValue = !!newValue;
  
              options.rtl = newValue;
  
              setNormalFill(options.normalFill);
              showRating();
          }
  
          function setMultiColor(colorOptions) {
  
              /*
               * called whenever one changes the `multiColor` option
               */
  
              options.multiColor = colorOptions;
  
              // set the recently set `ratedFill` option, if multiColor Options are unset
              setRatedFill(colorOptions ? colorOptions : ratedFill);
          }
  
          function setNumStars(newValue) {
  
              /*
               * Set the number of stars to use to display the rating, called whenever one
               * changes the `numStars` option
               */
  
              options.numStars = newValue;
  
              step = options.maxValue / options.numStars;
  
              $normalGroup.empty();
              $ratedGroup.empty();
  
              for (var i = 0; i < options.numStars; i++) {
  
                  $normalGroup.append($(options.starSvg || BASICSTAR));
                  $ratedGroup.append($(options.starSvg || BASICSTAR));
              }
  
              setStarWidth(options.starWidth);
              setNormalFill(options.normalFill);
              setSpacing(options.spacing);
  
              showRating();
  
              return $node;
          }
  
          function setMaxValue(newValue) {
  
              /*
               * set the Maximum Value of rating to be allowed, called whenever
               * one changes the `maxValue` option
               */
  
              options.maxValue = newValue;
  
              step = options.maxValue / options.numStars;
  
              if (options.rating > newValue) {
  
                  setRating(newValue);
              }
  
              showRating();
  
              return $node;
          }
  
          function setPrecision(newValue) {
  
              /*
               * Set the precision of the rating value, called if one changes the
               * `precision` option
               */
  
              options.precision = newValue;
  
              setRating(options.rating);
  
              return $node;
          }
  
          function setHalfStar(newValue) {
  
              /*
               * This function will be called if one changes the `halfStar` option
               */
  
              options.halfStar = newValue;
  
              return $node;
          }
  
          function setFullStar(newValue) {
  
              /*
               * This function will be called if one changes the `fullStar` option
               */
  
              options.fullStar = newValue;
  
              return $node;
          }
  
          function round(value) {
  
              /*
               * Rounds the value of rating if `halfStar` or `fullStar` options are chosen
               */
  
              var remainder = value % step,
                  halfStep = step / 2,
                  isHalfStar = options.halfStar,
                  isFullStar = options.fullStar;
  
              if (!isFullStar && !isHalfStar) {
  
                  return value;
              }
  
              if (isFullStar || (isHalfStar && remainder > halfStep)) {
  
                  value += step - remainder;
              } else {
  
                  value = value - remainder;
  
                  if (remainder > 0) {
  
                      value += halfStep;
                  }
              }
  
              return value;
          }
  
          function calculateRating(e) {
  
              /*
               * Calculates and returns the rating based on the position of cursor w.r.t the
               * plugin container
               */
  
              var position = $normalGroup.offset(),
                  nodeStartX = position.left,
                  nodeEndX = nodeStartX + $normalGroup.width();
  
              var maxValue = options.maxValue;
  
              // The x-coordinate(position) of the mouse pointer w.r.t page
              var pageX = e.pageX;
  
              var calculatedRating = 0;
  
              // If the mouse pointer is to the left of the container
              if (pageX < nodeStartX) {
  
                  calculatedRating = minValue;
              } else if (pageX > nodeEndX) { // If the mouse pointer is right of the container
  
                  calculatedRating = maxValue;
              } else { // If the mouse pointer is inside the continer
  
                  /*
                   * The fraction of width covered by the pointer w.r.t to the total width
                   * of the container.
                   */
                  var calcPrcnt = ((pageX - nodeStartX) / (nodeEndX - nodeStartX));
  
                  if (spacing > 0) {
  
                      /*
                       * If there is spacing between stars, take the percentage of width covered
                       * and subtract the percentage of width covered by stars and spacing, to find
                       * how many stars are covered, the number of stars covered is the rating
                       *
                       * TODO: I strongly feel that this logic can be improved!, Please help!
                       */
                      calcPrcnt *= 100;
  
                      var remPrcnt = calcPrcnt;
  
                      while (remPrcnt > 0) {
  
                          if (remPrcnt > percentOfStar) {
  
                              calculatedRating += step;
                              remPrcnt -= (percentOfStar + percentOfSpacing);
                          } else {
  
                              calculatedRating += remPrcnt / percentOfStar * step;
                              remPrcnt = 0;
                          }
                      }
                  } else {
  
                      /*
                       * If there is not spacing between stars, the fraction of width covered per
                       * `maxValue` is the rating
                       */
                      calculatedRating = calcPrcnt * (options.maxValue);
                  }
  
                  // Round the rating if `halfStar` or `fullStar` options are chosen
                  calculatedRating = round(calculatedRating);
              }
  
              if (options.rtl) {
  
                  calculatedRating = maxValue - calculatedRating;
              }
  
              return parseFloat(calculatedRating);
          }
  
          function setReadOnly(newValue) {
  
              /*
               * UnBinds mouse event handlers, called when whenever one changes the
               * `readOnly` option
               */
  
              options.readOnly = newValue;
  
              $node.attr("readonly", true);
  
              unbindEvents();
  
              if (!newValue) {
  
                  $node.removeAttr("readonly");
  
                  bindEvents();
              }
  
              return $node;
          }
  
          function setRating(newValue) {
  
              /*
               * Sets the rating of the Plugin, Called when option `rating` is changed
               * or, when `rating` method is called
               */
  
              var rating = newValue;
  
              var maxValue = options.maxValue;
  
              if (typeof rating === "string") {
  
                  // If rating is given in percentage, maxValue should be 100
                  if (rating[rating.length - 1] === "%") {
  
                      rating = rating.substr(0, rating.length - 1);
                      maxValue = 100;
  
                      setMaxValue(maxValue);
                  }
  
                  rating = parseFloat(rating);
              }
  
              checkBounds(rating, minValue, maxValue);
  
              rating = parseFloat(rating.toFixed(options.precision));
  
              checkPrecision(parseFloat(rating), minValue, maxValue);
  
              options.rating = rating;
  
              showRating();
  
              if (isInitialized) {
  
                  $node.trigger("rateyo.set", { rating: rating });
              }
  
              return $node;
          }
  
          function setOnInit(method) {
  
              /*
               * set what method to be called on Initialization
               */
  
              options.onInit = method;
  
              return $node;
          }
  
          function setOnSet(method) {
  
              /*
               * set what method to be called when rating is set
               */
  
              options.onSet = method;
  
              return $node;
          }
  
          function setOnChange(method) {
  
              /*
               * set what method to be called rating in the UI is changed
               */
  
              options.onChange = method;
  
              return $node;
          }
  
          this.rating = function(newValue) {
  
              /*
               * rating getter/setter
               */
  
              if (!isDefined(newValue)) {
  
                  return options.rating;
              }
  
              setRating(newValue);
  
              return $node;
          };
  
          this.destroy = function() {
  
              /*
               * Removes the Rating UI by clearing the content, and removing the custom classes
               */
  
              if (!options.readOnly) {
  
                  unbindEvents();
              }
  
              RateYo.prototype.collection = deleteInstance($node.get(0),
                  this.collection);
  
              $node.removeClass("jq-ry-container").children().remove();
  
              return $node;
          };
  
          this.method = function(methodName) {
  
              /*
               * Method to call the methods of RateYo Instance
               */
  
              if (!methodName) {
  
                  throw Error("Method name not specified!");
              }
  
              if (!isDefined(this[methodName])) {
  
                  throw Error("Method " + methodName + " doesn't exist!");
              }
  
              var args = Array.prototype.slice.apply(arguments, []),
                  params = args.slice(1),
                  method = this[methodName];
  
              return method.apply(this, params);
          };
  
          this.option = function(optionName, param) {
  
              /*
               * Method to get/set Options
               */
  
              if (!isDefined(optionName)) {
  
                  return options;
              }
  
              var method;
  
              switch (optionName) {
  
                  case "starWidth":
  
                      method = setStarWidth;
                      break;
                  case "numStars":
  
                      method = setNumStars;
                      break;
                  case "normalFill":
  
                      method = setNormalFill;
                      break;
                  case "ratedFill":
  
                      method = setRatedFill;
                      break;
                  case "multiColor":
  
                      method = setMultiColor;
                      break;
                  case "maxValue":
  
                      method = setMaxValue;
                      break;
                  case "precision":
  
                      method = setPrecision;
                      break;
                  case "rating":
  
                      method = setRating;
                      break;
                  case "halfStar":
  
                      method = setHalfStar;
                      break;
                  case "fullStar":
  
                      method = setFullStar;
                      break;
                  case "readOnly":
  
                      method = setReadOnly;
                      break;
                  case "spacing":
  
                      method = setSpacing;
                      break;
                  case "rtl":
  
                      method = setRtl;
                      break;
                  case "onInit":
  
                      method = setOnInit;
                      break;
                  case "onSet":
  
                      method = setOnSet;
                      break;
                  case "onChange":
  
                      method = setOnChange;
                      break;
                  default:
  
                      throw Error("No such option as " + optionName);
              }
  
              return isDefined(param) ? method(param) : options[optionName];
          };
  
          // function onMouseEnter(e) {
  
          //     /*
          //      * If the Mouse Pointer is inside the container, calculate and show the rating
          //      * in UI
          //      */
  
          //     var rating = calculateRating(e).toFixed(options.precision);
  
          //     var maxValue = options.maxValue;
  
          //     rating = checkPrecision(parseFloat(rating), minValue, maxValue);
  
          //     showRating(rating);
  
          //     $node.trigger("rateyo.change", { rating: rating });
          // }
  
          function onMouseLeave() {
              if (isMobileBrowser()) {
                  return;
              }
  
              /*
               * If mouse leaves, revert the rating in UI to previously set rating,
               * when empty value is passed to showRating, it will take the previously set
               * rating
               */
  
              showRating();
  
              $node.trigger("rateyo.change", { rating: options.rating });
          }
  
          function onMouseClick(e) {
  
              /*
               * On clicking the mouse inside the container, calculate and set the rating
               */
              e.preventDefault()
                  // var resultantRating = calculateRating(e).toFixed(options.precision);
                  // resultantRating = parseFloat(resultantRating);
  
              // that.rating(resultantRating);
          }
  
          function onInit(e, data) {
  
              if (options.onInit && typeof options.onInit === "function") {
  
                  /* jshint validthis:true */
                  options.onInit.apply(this, [data.rating, that]);
              }
          }
  
          function onChange(e, data) {
  
              if (options.onChange && typeof options.onChange === "function") {
  
                  /* jshint validthis:true */
                  options.onChange.apply(this, [data.rating, that]);
              }
          }
  
          function onSet(e, data) {
  
              if (options.onSet && typeof options.onSet === "function") {
  
                  /* jshint validthis:true */
                  options.onSet.apply(this, [data.rating, that]);
              }
          }
  
          function bindEvents() {
  
              // .on("mousemove", onMouseEnter)
              //     .on("mouseenter", onMouseEnter)
              $node.on("mouseleave", onMouseLeave)
                  .on("click", onMouseClick)
                  .on("rateyo.init", onInit)
                  .on("rateyo.change", onChange)
                  .on("rateyo.set", onSet);
          }
  
          function unbindEvents() {
  
              // .off("mousemove", onMouseEnter)
              //     .off("mouseenter", onMouseEnter)
              $node.off("mouseleave", onMouseLeave)
                  .off("click", onMouseClick)
                  .off("rateyo.init", onInit)
                  .off("rateyo.change", onChange)
                  .off("rateyo.set", onSet);
          }
  
          setNumStars(options.numStars);
          setReadOnly(options.readOnly);
  
          if (options.rtl) {
  
              setRtl(options.rtl);
          }
  
          this.collection.push(this);
          this.rating(options.rating, true);
  
          isInitialized = true;
          $node.trigger("rateyo.init", { rating: options.rating });
      }
  
      RateYo.prototype.collection = [];
  
      function getInstance(node, collection) {
  
          /*
           * Given a HTML element (node) and a collection of RateYo instances,
           * this function will search through the collection and return the matched
           * instance having the node
           */
  
          var instance;
  
          $.each(collection, function() {
  
              if (node === this.node) {
  
                  instance = this;
                  return false;
              }
          });
  
          return instance;
      }
  
      function deleteInstance(node, collection) {
  
          /*
           * Given a HTML element (node) and a collection of RateYo instances,
           * this function will search through the collection and delete the
           * instance having the node, and return the modified collection
           */
  
          $.each(collection, function(index) {
  
              if (node === this.node) {
  
                  var firstPart = collection.slice(0, index),
                      secondPart = collection.slice(index + 1, collection.length);
  
                  collection = firstPart.concat(secondPart);
  
                  return false;
              }
          });
  
          return collection;
      }
  
      function _rateYo(options) {
  
          var rateYoInstances = RateYo.prototype.collection;
  
          /* jshint validthis:true */
          var $nodes = $(this);
  
          if ($nodes.length === 0) {
  
              return $nodes;
          }
  
          var args = Array.prototype.slice.apply(arguments, []);
  
          if (args.length === 0) {
  
              //If args length is 0, Initialize the UI with default settings
              options = args[0] = {};
          } else if (args.length === 1 && typeof args[0] === "object") {
  
              //If an Object is specified as first argument, it is considered as options
              options = args[0];
          } else if (args.length >= 1 && typeof args[0] === "string") {
  
              /*
               * if there is only one argument, and if its a string, it is supposed to be a
               * method name, if more than one argument is specified, the remaining arguments
               * except the first argument, will be passed as a params to the specified method
               */
  
              var methodName = args[0],
                  params = args.slice(1);
  
              var result = [];
  
              $.each($nodes, function(i, node) {
  
                  var existingInstance = getInstance(node, rateYoInstances);
  
                  if (!existingInstance) {
  
                      throw Error("Trying to set options before even initialization");
                  }
  
                  var method = existingInstance[methodName];
  
                  if (!method) {
  
                      throw Error("Method " + methodName + " does not exist!");
                  }
  
                  var returnVal = method.apply(existingInstance, params);
  
                  result.push(returnVal);
              });
  
              /*
               * If the plugin in being called on only one jQuery Element, return only the
               * first value, to support chaining.
               */
              result = result.length === 1 ? result[0] : result;
  
              return result;
          } else {
  
              throw Error("Invalid Arguments");
          }
  
          /*
           * if only options are passed, extend default options, and if the plugin is not
           * initialized on a particular jQuery element, initalize RateYo on it
           */
          options = $.extend({}, DEFAULTS, options);
  
          return $.each($nodes, function() {
  
              var existingInstance = getInstance(this, rateYoInstances);
  
              if (existingInstance) {
  
                  return existingInstance;
              }
  
              var $node = $(this),
                  dataAttrs = {},
                  optionsCopy = $.extend({}, options);
  
              $.each($node.data(), function(key, value) {
  
                  if (key.indexOf("rateyo") !== 0) {
  
                      return;
                  }
  
                  var optionName = key.replace(/^rateyo/, "");
  
                  optionName = optionName[0].toLowerCase() + optionName.slice(1);
  
                  dataAttrs[optionName] = value;
  
                  delete optionsCopy[optionName];
              });
  
              return new RateYo($(this), $.extend({}, dataAttrs, optionsCopy));
          });
      }
  
      function rateYo() {
  
          /* jshint validthis:true */
          return _rateYo.apply(this, Array.prototype.slice.apply(arguments, []));
      }
  
      window.RateYo = RateYo;
      $.fn.rateYo = rateYo;
  
  }(window.jQuery));