/*
* jPicker 1.1.6
*
* jQuery Plugin for Photoshop style color picker
*
* Copyright (c) 2010 Christopher T. Tillman
* Digital Magic Productions, Inc. (http://www.digitalmagicpro.com/)
* MIT style license, FREE to use, alter, copy, sell, and especially ENHANCE
*
* Painstakingly ported from John Dyers' excellent work on his own color picker based on the Prototype framework.
*
* John Dyers' website: (http://johndyer.name)
* Color Picker page:   (http://johndyer.name/post/2007/09/PhotoShop-like-JavaScript-Color-Picker.aspx)
*
*/

var zIndexNewValue = 200000;
(function ($, version) {
    Math.precision = function (value, precision) {
        if (precision === undefined) precision = 0;
        return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision);
    };
    var Slider = // encapsulate slider functionality for the ColorMap and ColorBar - could be useful to use a jQuery UI draggable for this with certain extensions
      function (bar, options) {
          var $this = this, // private properties, methods, and events - keep these variables and classes invisible to outside code
          arrow = bar.find('img:first'), // the arrow image to drag
          minX = 0,
          maxX = 100,
          rangeX = 100,
          minY = 0,
          maxY = 100,
          rangeY = 100,
          x = 0,
          y = 0,
          offset,
          timeout,
          changeEvents = new Array(),
          fireChangeEvents =
            function (context) {
                for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context);
            },
          mouseDown = // bind the mousedown to the bar not the arrow for quick snapping to the clicked location
            function (e) {
                var off = bar.offset();
                offset = { l: off.left | 0, t: off.top | 0 };
                clearTimeout(timeout);
                timeout = setTimeout( // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run
                function () {
                    setValuesFromMousePosition.call($this, e);
                }, 0);
                // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing
                $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp);
                e.preventDefault(); // don't try to select anything or drag the image to the desktop
            },
          mouseMove = // set the values as the mouse moves
            function (e) {
                clearTimeout(timeout);
                timeout = setTimeout(
                function () {
                    setValuesFromMousePosition.call($this, e);
                }, 0);
                e.stopPropagation();
                e.preventDefault();
                return false;
            },
          mouseUp = // unbind the document events - they aren't needed when not dragging
            function (e) {
                $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove);
                e.stopPropagation();
                e.preventDefault();
                return false;
            },
          setValuesFromMousePosition = // calculate mouse position and set value within the current range
            function (e) {
                var locX = e.pageX - offset.l,
                  locY = e.pageY - offset.t,
                  barW = bar.w, // local copies for YUI compressor
                  barH = bar.h;
                // keep the arrow within the bounds of the bar
                if (locX < 0) locX = 0;
                else if (locX > barW) locX = barW;
                if (locY < 0) locY = 0;
                else if (locY > barH) locY = barH;
                val.call($this, 'xy', { x: ((locX / barW) * rangeX) + minX, y: ((locY / barH) * rangeY) + minY });
            },
          draw =
            function () {
                var arrowOffsetX = 0,
                arrowOffsetY = 0,
                barW = bar.w,
                barH = bar.h,
                arrowW = arrow.w,
                arrowH = arrow.h;
                setTimeout(
                function () {
                    if (rangeX > 0) // range is greater than zero
                    {
                        // constrain to bounds
                        if (x == maxX) arrowOffsetX = barW;
                        else arrowOffsetX = ((x / rangeX) * barW) | 0;
                    }
                    if (rangeY > 0) // range is greater than zero
                    {
                        // constrain to bounds
                        if (y == maxY) arrowOffsetY = barH;
                        else arrowOffsetY = ((y / rangeY) * barH) | 0;
                    }
                    // if arrow width is greater than bar width, center arrow and prevent horizontal dragging
                    if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest)
                    else arrowOffsetX -= arrowW >> 1;
                    // if arrow height is greater than bar height, center arrow and prevent vertical dragging
                    if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1);
                    else arrowOffsetY -= arrowH >> 1;
                    // set the arrow position based on these offsets
                    arrow.css({ left: arrowOffsetX + 'px', top: arrowOffsetY + 'px' });
                }, 0);
            },
          val =
            function (name, value, context) {
                var set = value !== undefined;
                if (!set) {
                    if (name === undefined || name == null) name = 'xy';
                    switch (name.toLowerCase()) {
                        case 'x': return x;
                        case 'y': return y;
                        case 'xy':
                        default: return { x: x, y: y };
                    }
                }
                if (context != null && context == $this) return;
                var changed = false,
                  newX,
                  newY;
                if (name == null) name = 'xy';
                switch (name.toLowerCase()) {
                    case 'x':
                        newX = value && (value.x && value.x | 0 || value | 0) || 0;
                        break;
                    case 'y':
                        newY = value && (value.y && value.y | 0 || value | 0) || 0;
                        break;
                    case 'xy':
                    default:
                        newX = value && value.x && value.x | 0 || 0;
                        newY = value && value.y && value.y | 0 || 0;
                        break;
                }
                if (newX != null) {
                    if (newX < minX) newX = minX;
                    else if (newX > maxX) newX = maxX;
                    if (x != newX) {
                        x = newX;
                        changed = true;
                    }
                }
                if (newY != null) {
                    if (newY < minY) newY = minY;
                    else if (newY > maxY) newY = maxY;
                    if (y != newY) {
                        y = newY;
                        changed = true;
                    }
                }
                changed && fireChangeEvents.call($this, context || $this);
            },
          range =
            function (name, value) {
                var set = value !== undefined;
                if (!set) {
                    if (name === undefined || name == null) name = 'all';
                    switch (name.toLowerCase()) {
                        case 'minx': return minX;
                        case 'maxx': return maxX;
                        case 'rangex': return { minX: minX, maxX: maxX, rangeX: rangeX };
                        case 'miny': return minY;
                        case 'maxy': return maxY;
                        case 'rangey': return { minY: minY, maxY: maxY, rangeY: rangeY };
                        case 'all':
                        default: return { minX: minX, maxX: maxX, rangeX: rangeX, minY: minY, maxY: maxY, rangeY: rangeY };
                    }
                }
                var changed = false,
                  newMinX,
                  newMaxX,
                  newMinY,
                  newMaxY;
                if (name == null) name = 'all';
                switch (name.toLowerCase()) {
                    case 'minx':
                        newMinX = value && (value.minX && value.minX | 0 || value | 0) || 0;
                        break;
                    case 'maxx':
                        newMaxX = value && (value.maxX && value.maxX | 0 || value | 0) || 0;
                        break;
                    case 'rangex':
                        newMinX = value && value.minX && value.minX | 0 || 0;
                        newMaxX = value && value.maxX && value.maxX | 0 || 0;
                        break;
                    case 'miny':
                        newMinY = value && (value.minY && value.minY | 0 || value | 0) || 0;
                        break;
                    case 'maxy':
                        newMaxY = value && (value.maxY && value.maxY | 0 || value | 0) || 0;
                        break;
                    case 'rangey':
                        newMinY = value && value.minY && value.minY | 0 || 0;
                        newMaxY = value && value.maxY && value.maxY | 0 || 0;
                        break;
                    case 'all':
                    default:
                        newMinX = value && value.minX && value.minX | 0 || 0;
                        newMaxX = value && value.maxX && value.maxX | 0 || 0;
                        newMinY = value && value.minY && value.minY | 0 || 0;
                        newMaxY = value && value.maxY && value.maxY | 0 || 0;
                        break;
                }
                if (newMinX != null && minX != newMinX) {
                    minX = newMinX;
                    rangeX = maxX - minX;
                }
                if (newMaxX != null && maxX != newMaxX) {
                    maxX = newMaxX;
                    rangeX = maxX - minX;
                }
                if (newMinY != null && minY != newMinY) {
                    minY = newMinY;
                    rangeY = maxY - minY;
                }
                if (newMaxY != null && maxY != newMaxY) {
                    maxY = newMaxY;
                    rangeY = maxY - minY;
                }
            },
          bind =
            function (callback) {
                if ($.isFunction(callback)) changeEvents.push(callback);
            },
          unbind =
            function (callback) {
                if (!$.isFunction(callback)) return;
                var i;
                while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1);
            },
          destroy =
            function () {
                // unbind all possible events and null objects
                $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove);
                bar.unbind('mousedown', mouseDown);
                bar = null;
                arrow = null;
                changeEvents = null;
            };
          $.extend(true, $this, // public properties, methods, and event bindings - these we need to access from other controls
          {
          val: val,
          range: range,
          bind: bind,
          unbind: unbind,
          destroy: destroy
      });
      // initialize this control
      arrow.src = options.arrow && options.arrow.image;
      arrow.w = options.arrow && options.arrow.width || arrow.width();
      arrow.h = options.arrow && options.arrow.height || arrow.height();
      bar.w = options.map && options.map.width || bar.width();
      bar.h = options.map && options.map.height || bar.height();
      // bind mousedown event
      bar.bind('mousedown', mouseDown);
      bind.call($this, draw);
  },
    ColorValuePicker = // controls for all the input elements for the typing in color values
      function (picker, color, bindedHex, alphaPrecision) {
          var $this = this, // private properties and methods
          inputs = picker.find('td.Text input'),
          red = inputs.eq(3),
          green = inputs.eq(4),
          blue = inputs.eq(5),
          alpha = inputs.length > 7 ? inputs.eq(6) : null,
          hue = inputs.eq(0),
          saturation = inputs.eq(1),
          value = inputs.eq(2),
          hex = inputs.eq(inputs.length > 7 ? 7 : 6),
          ahex = inputs.length > 7 ? inputs.eq(8) : null,
          keyDown = // input box key down - use arrows to alter color
            function (e) {
                if (e.target.value == '' && e.target != hex.get(0) && (bindedHex != null && e.target != bindedHex.get(0) || bindedHex == null)) return;
                if (!validateKey(e)) return e;
                switch (e.target) {
                    case red.get(0):
                        switch (e.keyCode) {
                            case 38:
                                red.val(setValueInRange.call($this, (red.val() << 0) + 1, 0, 255));
                                color.val('r', red.val(), e.target);
                                return false;
                            case 40:
                                red.val(setValueInRange.call($this, (red.val() << 0) - 1, 0, 255));
                                color.val('r', red.val(), e.target);
                                return false;
                        }
                        break;
                    case green.get(0):
                        switch (e.keyCode) {
                            case 38:
                                green.val(setValueInRange.call($this, (green.val() << 0) + 1, 0, 255));
                                color.val('g', green.val(), e.target);
                                return false;
                            case 40:
                                green.val(setValueInRange.call($this, (green.val() << 0) - 1, 0, 255));
                                color.val('g', green.val(), e.target);
                                return false;
                        }
                        break;
                    case blue.get(0):
                        switch (e.keyCode) {
                            case 38:
                                blue.val(setValueInRange.call($this, (blue.val() << 0) + 1, 0, 255));
                                color.val('b', blue.val(), e.target);
                                return false;
                            case 40:
                                blue.val(setValueInRange.call($this, (blue.val() << 0) - 1, 0, 255));
                                color.val('b', blue.val(), e.target);
                                return false;
                        }
                        break;
                    case alpha && alpha.get(0):
                        switch (e.keyCode) {
                            case 38:
                                alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) + 1, 0, 100));
                                color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target);
                                return false;
                            case 40:
                                alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) - 1, 0, 100));
                                color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target);
                                return false;
                        }
                        break;
                    case hue.get(0):
                        switch (e.keyCode) {
                            case 38:
                                hue.val(setValueInRange.call($this, (hue.val() << 0) + 1, 0, 360));
                                color.val('h', hue.val(), e.target);
                                return false;
                            case 40:
                                hue.val(setValueInRange.call($this, (hue.val() << 0) - 1, 0, 360));
                                color.val('h', hue.val(), e.target);
                                return false;
                        }
                        break;
                    case saturation.get(0):
                        switch (e.keyCode) {
                            case 38:
                                saturation.val(setValueInRange.call($this, (saturation.val() << 0) + 1, 0, 100));
                                color.val('s', saturation.val(), e.target);
                                return false;
                            case 40:
                                saturation.val(setValueInRange.call($this, (saturation.val() << 0) - 1, 0, 100));
                                color.val('s', saturation.val(), e.target);
                                return false;
                        }
                        break;
                    case value.get(0):
                        switch (e.keyCode) {
                            case 38:
                                value.val(setValueInRange.call($this, (value.val() << 0) + 1, 0, 100));
                                color.val('v', value.val(), e.target);
                                return false;
                            case 40:
                                value.val(setValueInRange.call($this, (value.val() << 0) - 1, 0, 100));
                                color.val('v', value.val(), e.target);
                                return false;
                        }
                        break;
                }
            },
          keyUp = // input box key up - validate value and set color
            function (e) {
                if (e.target.value == '' && e.target != hex.get(0) && (bindedHex != null && e.target != bindedHex.get(0) || bindedHex == null)) return;
                if (!validateKey(e)) return e;
                switch (e.target) {
                    case red.get(0):
                        red.val(setValueInRange.call($this, red.val(), 0, 255));
                        color.val('r', red.val(), e.target);
                        break;
                    case green.get(0):
                        green.val(setValueInRange.call($this, green.val(), 0, 255));
                        color.val('g', green.val(), e.target);
                        break;
                    case blue.get(0):
                        blue.val(setValueInRange.call($this, blue.val(), 0, 255));
                        color.val('b', blue.val(), e.target);
                        break;
                    case alpha && alpha.get(0):
                        alpha.val(setValueInRange.call($this, alpha.val(), 0, 100));
                        color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target);
                        break;
                    case hue.get(0):
                        hue.val(setValueInRange.call($this, hue.val(), 0, 360));
                        color.val('h', hue.val(), e.target);
                        break;
                    case saturation.get(0):
                        saturation.val(setValueInRange.call($this, saturation.val(), 0, 100));
                        color.val('s', saturation.val(), e.target);
                        break;
                    case value.get(0):
                        value.val(setValueInRange.call($this, value.val(), 0, 100));
                        color.val('v', value.val(), e.target);
                        break;
                    case hex.get(0):
                        hex.val(hex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6));
                        bindedHex && bindedHex.val(hex.val());
                        color.val('hex', hex.val() != '' ? hex.val() : null, e.target);
                        break;
                    case bindedHex && bindedHex.get(0):
                        bindedHex.val(bindedHex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6));
                        hex.val(bindedHex.val());
                        color.val('hex', bindedHex.val() != '' ? bindedHex.val() : null, e.target);
                        break;
                    case ahex && ahex.get(0):
                        ahex.val(ahex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 2));
                        color.val('a', ahex.val() != null ? parseInt(ahex.val(), 16) : null, e.target);
                        break;
                }
            },
          blur = // input box blur - reset to original if value empty
            function (e) {
                if (color.val() != null) {
                    switch (e.target) {
                        case red.get(0): red.val(color.val('r')); break;
                        case green.get(0): green.val(color.val('g')); break;
                        case blue.get(0): blue.val(color.val('b')); break;
                        case alpha && alpha.get(0): alpha.val(Math.precision((color.val('a') * 100) / 255, alphaPrecision)); break;
                        case hue.get(0): hue.val(color.val('h')); break;
                        case saturation.get(0): saturation.val(color.val('s')); break;
                        case value.get(0): value.val(color.val('v')); break;
                        case hex.get(0):
                        case bindedHex && bindedHex.get(0):
                            hex.val(color.val('hex'));
                            bindedHex && bindedHex.val(color.val('hex'));
                            break;
                        case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break;
                    }
                }
            },
          validateKey = // validate key
            function (e) {
                switch (e.keyCode) {
                    case 9:
                    case 16:
                    case 29:
                    case 37:
                    case 39:
                        return false;
                    case 'c'.charCodeAt():
                    case 'v'.charCodeAt():
                        if (e.ctrlKey) return false;
                }
                return true;
            },
          setValueInRange = // constrain value within range
            function (value, min, max) {
                if (value == '' || isNaN(value)) return min;
                if (value > max) return max;
                if (value < min) return min;
                return value;
            },
          colorChanged =
            function (ui, context) {
                var all = ui.val('all');
                if (context != red.get(0)) red.val(all != null ? all.r : '');
                if (context != green.get(0)) green.val(all != null ? all.g : '');
                if (context != blue.get(0)) blue.val(all != null ? all.b : '');
                if (alpha && context != alpha.get(0)) alpha.val(all != null ? Math.precision((all.a * 100) / 255, alphaPrecision) : '');
                if (context != hue.get(0)) hue.val(all != null ? all.h : '');
                if (context != saturation.get(0)) saturation.val(all != null ? all.s : '');
                if (context != value.get(0)) value.val(all != null ? all.v : '');
                if (context != hex.get(0) && (bindedHex && context != bindedHex.get(0) || !bindedHex)) hex.val(all != null ? all.hex : '');
                if (bindedHex && context != bindedHex.get(0) && context != hex.get(0)) bindedHex.val(all != null ? all.hex : '');
                if (ahex && context != ahex.get(0)) ahex.val(all != null ? all.ahex.substring(6) : '');
            },
          destroy =
            function () {
                // unbind all events and null objects
                red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur);
                red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown);
                color.unbind(colorChanged);
                red = null;
                green = null;
                blue = null;
                alpha = null;
                hue = null;
                saturation = null;
                value = null;
                hex = null;
                ahex = null;
            };
          $.extend(true, $this, // public properties and methods
          {
          destroy: destroy
      });
      red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur);
      red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown);
      color.bind(colorChanged);
  };
    $.jPicker =
    {
        List: [], // array holding references to each active instance of the control
        Color: // color object - we will be able to assign by any color space type or retrieve any color space info
        // we want this public so we can optionally assign new color objects to initial values using inputs other than a string hex value (also supported)
        function (init) {
            var $this = this,
            r,
            g,
            b,
            a,
            h,
            s,
            v,
            changeEvents = new Array(),
            fireChangeEvents =
              function (context) {
                  for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context);
              },
            val =
              function (name, value, context) {
                  var set = value !== undefined;
                  if (!set) {
                      if (name === undefined || name == null || name == '') name = 'all';
                      if (r == null) return null;
                      switch (name.toLowerCase()) {
                          case 'ahex': return ColorMethods.rgbaToHex({ r: r, g: g, b: b, a: a });
                          case 'hex': return val('ahex').substring(0, 6);
                          case 'all': return { r: r, g: g, b: b, a: a, h: h, s: s, v: v, hex: val.call($this, 'hex'), ahex: val.call($this, 'ahex') };
                          default:
                              var ret = {};
                              for (var i = 0; i < name.length; i++) {
                                  switch (name.charAt(i)) {
                                      case 'r':
                                          if (name.length == 1) ret = r;
                                          else ret.r = r;
                                          break;
                                      case 'g':
                                          if (name.length == 1) ret = g;
                                          else ret.g = g;
                                          break;
                                      case 'b':
                                          if (name.length == 1) ret = b;
                                          else ret.b = b;
                                          break;
                                      case 'a':
                                          if (name.length == 1) ret = a;
                                          else ret.a = a;
                                          break;
                                      case 'h':
                                          if (name.length == 1) ret = h;
                                          else ret.h = h;
                                          break;
                                      case 's':
                                          if (name.length == 1) ret = s;
                                          else ret.s = s;
                                          break;
                                      case 'v':
                                          if (name.length == 1) ret = v;
                                          else ret.v = v;
                                          break;
                                  }
                              }
                              return ret == {} ? val.call($this, 'all') : ret;
                              break;
                      }
                  }
                  if (context != null && context == $this) return;
                  var changed = false;
                  if (name == null) name = '';
                  if (value == null) {
                      if (r != null) {
                          r = null;
                          changed = true;
                      }
                      if (g != null) {
                          g = null;
                          changed = true;
                      }
                      if (b != null) {
                          b = null;
                          changed = true;
                      }
                      if (a != null) {
                          a = null;
                          changed = true;
                      }
                      if (h != null) {
                          h = null;
                          changed = true;
                      }
                      if (s != null) {
                          s = null;
                          changed = true;
                      }
                      if (v != null) {
                          v = null;
                          changed = true;
                      }
                      changed && fireChangeEvents.call($this, context || $this);
                      return;
                  }
                  switch (name.toLowerCase()) {
                      case 'ahex':
                      case 'hex':
                          var ret = ColorMethods.hexToRgba(value && (value.ahex || value.hex) || value || '00000000');
                          val.call($this, 'rgba', { r: ret.r, g: ret.g, b: ret.b, a: name == 'ahex' ? ret.a : a != null ? a : 255 }, context);
                          break;
                      default:
                          if (value && (value.ahex != null || value.hex != null)) {
                              val.call($this, 'ahex', value.ahex || value.hex || '00000000', context);
                              return;
                          }
                          var newV = {}, rgb = false, hsv = false;
                          if (value.r !== undefined && !name.indexOf('r') == -1) name += 'r';
                          if (value.g !== undefined && !name.indexOf('g') == -1) name += 'g';
                          if (value.b !== undefined && !name.indexOf('b') == -1) name += 'b';
                          if (value.a !== undefined && !name.indexOf('a') == -1) name += 'a';
                          if (value.h !== undefined && !name.indexOf('h') == -1) name += 'h';
                          if (value.s !== undefined && !name.indexOf('s') == -1) name += 's';
                          if (value.v !== undefined && !name.indexOf('v') == -1) name += 'v';
                          for (var i = 0; i < name.length; i++) {
                              switch (name.charAt(i)) {
                                  case 'r':
                                      if (hsv) continue;
                                      rgb = true;
                                      newV.r = value && value.r && value.r | 0 || value && value | 0 || 0;
                                      if (newV.r < 0) newV.r = 0;
                                      else if (newV.r > 255) newV.r = 255;
                                      if (r != newV.r) {
                                          r = newV.r;
                                          changed = true;
                                      }
                                      break;
                                  case 'g':
                                      if (hsv) continue;
                                      rgb = true;
                                      newV.g = value && value.g && value.g | 0 || value && value | 0 || 0;
                                      if (newV.g < 0) newV.g = 0;
                                      else if (newV.g > 255) newV.g = 255;
                                      if (g != newV.g) {
                                          g = newV.g;
                                          changed = true;
                                      }
                                      break;
                                  case 'b':
                                      if (hsv) continue;
                                      rgb = true;
                                      newV.b = value && value.b && value.b | 0 || value && value | 0 || 0;
                                      if (newV.b < 0) newV.b = 0;
                                      else if (newV.b > 255) newV.b = 255;
                                      if (b != newV.b) {
                                          b = newV.b;
                                          changed = true;
                                      }
                                      break;
                                  case 'a':
                                      newV.a = value && value.a != null ? value.a | 0 : value != null ? value | 0 : 255;
                                      if (newV.a < 0) newV.a = 0;
                                      else if (newV.a > 255) newV.a = 255;
                                      if (a != newV.a) {
                                          a = newV.a;
                                          changed = true;
                                      }
                                      break;
                                  case 'h':
                                      if (rgb) continue;
                                      hsv = true;
                                      newV.h = value && value.h && value.h | 0 || value && value | 0 || 0;
                                      if (newV.h < 0) newV.h = 0;
                                      else if (newV.h > 360) newV.h = 360;
                                      if (h != newV.h) {
                                          h = newV.h;
                                          changed = true;
                                      }
                                      break;
                                  case 's':
                                      if (rgb) continue;
                                      hsv = true;
                                      newV.s = value && value.s != null ? value.s | 0 : value != null ? value | 0 : 100;
                                      if (newV.s < 0) newV.s = 0;
                                      else if (newV.s > 100) newV.s = 100;
                                      if (s != newV.s) {
                                          s = newV.s;
                                          changed = true;
                                      }
                                      break;
                                  case 'v':
                                      if (rgb) continue;
                                      hsv = true;
                                      newV.v = value && value.v != null ? value.v | 0 : value != null ? value | 0 : 100;
                                      if (newV.v < 0) newV.v = 0;
                                      else if (newV.v > 100) newV.v = 100;
                                      if (v != newV.v) {
                                          v = newV.v;
                                          changed = true;
                                      }
                                      break;
                              }
                          }
                          if (changed) {
                              if (rgb) {
                                  r = r || 0;
                                  g = g || 0;
                                  b = b || 0;
                                  var ret = ColorMethods.rgbToHsv({ r: r, g: g, b: b });
                                  h = ret.h;
                                  s = ret.s;
                                  v = ret.v;
                              }
                              else if (hsv) {
                                  h = h || 0;
                                  s = s != null ? s : 100;
                                  v = v != null ? v : 100;
                                  var ret = ColorMethods.hsvToRgb({ h: h, s: s, v: v });
                                  r = ret.r;
                                  g = ret.g;
                                  b = ret.b;
                              }
                              a = a != null ? a : 255;
                              fireChangeEvents.call($this, context || $this);
                          }
                          break;
                  }
              },
            bind =
              function (callback) {
                  if ($.isFunction(callback)) changeEvents.push(callback);
              },
            unbind =
              function (callback) {
                  if (!$.isFunction(callback)) return;
                  var i;
                  while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1);
              },
            destroy =
              function () {
                  changeEvents = null;
              }
            $.extend(true, $this, // public properties and methods
            {
            val: val,
            bind: bind,
            unbind: unbind,
            destroy: destroy
        });
        if (init) {
            if (init.ahex != null) val('ahex', init);
            else if (init.hex != null) val((init.a != null ? 'a' : '') + 'hex', init.a != null ? { ahex: init.hex + ColorMethods.intToHex(init.a)} : init);
            else if (init.r != null && init.g != null && init.b != null) val('rgb' + (init.a != null ? 'a' : ''), init);
            else if (init.h != null && init.s != null && init.v != null) val('hsv' + (init.a != null ? 'a' : ''), init);
        }
    },
    ColorMethods: // color conversion methods  - make public to give use to external scripts
        {
        hexToRgba:
            function (hex) {
                hex = this.validateHex(hex);
                if (hex == '') return { r: null, g: null, b: null, a: null };
                var r = '00', g = '00', b = '00', a = '255';
                if (hex.length == 6) hex += 'ff';
                if (hex.length > 6) {
                    r = hex.substring(0, 2);
                    g = hex.substring(2, 4);
                    b = hex.substring(4, 6);
                    a = hex.substring(6, hex.length);
                }
                else {
                    if (hex.length > 4) {
                        r = hex.substring(4, hex.length);
                        hex = hex.substring(0, 4);
                    }
                    if (hex.length > 2) {
                        g = hex.substring(2, hex.length);
                        hex = hex.substring(0, 2);
                    }
                    if (hex.length > 0) b = hex.substring(0, hex.length);
                }
                return { r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) };
            },
        validateHex:
            function (hex) {
                hex = hex.toLowerCase().replace(/[^a-f0-9]/g, '');
                if (hex.length > 8) hex = hex.substring(0, 8);
                return hex;
            },
        rgbaToHex:
            function (rgba) {
                return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a);
            },
        intToHex:
            function (dec) {
                var result = (dec | 0).toString(16);
                if (result.length == 1) result = ('0' + result);
                return result.toLowerCase();
            },
        hexToInt:
            function (hex) {
                return parseInt(hex, 16);
            },
        rgbToHsv:
            function (rgb) {
                var r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = { h: 0, s: 0, v: 0 }, min = 0, max = 0, delta;
                if (r >= g && r >= b) {
                    max = r;
                    min = g > b ? b : g;
                }
                else if (g >= b && g >= r) {
                    max = g;
                    min = r > b ? b : r;
                }
                else {
                    max = b;
                    min = g > r ? r : g;
                }
                hsv.v = max;
                hsv.s = max ? (max - min) / max : 0;
                if (!hsv.s) hsv.h = 0;
                else {
                    delta = max - min;
                    if (r == max) hsv.h = (g - b) / delta;
                    else if (g == max) hsv.h = 2 + (b - r) / delta;
                    else hsv.h = 4 + (r - g) / delta;
                    hsv.h = parseInt(hsv.h * 60);
                    if (hsv.h < 0) hsv.h += 360;
                }
                hsv.s = (hsv.s * 100) | 0;
                hsv.v = (hsv.v * 100) | 0;
                return hsv;
            },
        hsvToRgb:
            function (hsv) {
                var rgb = { r: 0, g: 0, b: 0, a: 100 }, h = hsv.h, s = hsv.s, v = hsv.v;
                if (s == 0) {
                    if (v == 0) rgb.r = rgb.g = rgb.b = 0;
                    else rgb.r = rgb.g = rgb.b = (v * 255 / 100) | 0;
                }
                else {
                    if (h == 360) h = 0;
                    h /= 60;
                    s = s / 100;
                    v = v / 100;
                    var i = h | 0,
                    f = h - i,
                    p = v * (1 - s),
                    q = v * (1 - (s * f)),
                    t = v * (1 - (s * (1 - f)));
                    switch (i) {
                        case 0:
                            rgb.r = v;
                            rgb.g = t;
                            rgb.b = p;
                            break;
                        case 1:
                            rgb.r = q;
                            rgb.g = v;
                            rgb.b = p;
                            break;
                        case 2:
                            rgb.r = p;
                            rgb.g = v;
                            rgb.b = t;
                            break;
                        case 3:
                            rgb.r = p;
                            rgb.g = q;
                            rgb.b = v;
                            break;
                        case 4:
                            rgb.r = t;
                            rgb.g = p;
                            rgb.b = v;
                            break;
                        case 5:
                            rgb.r = v;
                            rgb.g = p;
                            rgb.b = q;
                            break;
                    }
                    rgb.r = (rgb.r * 255) | 0;
                    rgb.g = (rgb.g * 255) | 0;
                    rgb.b = (rgb.b * 255) | 0;
                }
                return rgb;
            }
    }
};
var Color = $.jPicker.Color, List = $.jPicker.List, ColorMethods = $.jPicker.ColorMethods; // local copies for YUI compressor
$.fn.jPicker =
    function (options) {
        var $arguments = arguments;
        return this.each(
        function () {
            var $this = this, settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor
            if ($($this).get(0).nodeName.toLowerCase() == 'input') // Add color picker icon if binding to an input element and bind the events to the input
            {
                $.extend(true, settings,
              {
                  window:
                {
                    bindToInput: true,
                    expandable: true,
                    input: $($this)
                }
              });
                if ($($this).val() == '') {
                    settings.color.active = new Color({ hex: null });
                    settings.color.current = new Color({ hex: null });
                }
                else if (ColorMethods.validateHex($($this).val())) {
                    settings.color.active = new Color({ hex: $($this).val(), a: settings.color.active.val('a') });
                    settings.color.current = new Color({ hex: $($this).val(), a: settings.color.active.val('a') });
                }
            }
            if (settings.window.expandable)
                $($this).after('<span class="jPicker"><span class="Icon"><span class="Color">&nbsp;</span><span class="Alpha">&nbsp;</span><span class="Image" title="Click To Open Color Picker">&nbsp;</span><span class="Container">&nbsp;</span></span></span>');
            else settings.window.liveUpdate = false; // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results
            var isLessThanIE7 = parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters, // needed to run the AlphaImageLoader function for IE6
            container = null,
            colorMapDiv = null,
            colorBarDiv = null,
            colorMapL1 = null, // different layers of colorMap and colorBar
            colorMapL2 = null,
            colorMapL3 = null,
            colorBarL1 = null,
            colorBarL2 = null,
            colorBarL3 = null,
            colorBarL4 = null,
            colorBarL5 = null,
            colorBarL6 = null,
            colorMap = null, // color maps
            colorBar = null,
            colorPicker = null,
            elementStartX = null, // Used to record the starting css positions for dragging the control
            elementStartY = null,
            pageStartX = null, // Used to record the mousedown coordinates for dragging the control
            pageStartY = null,
            activePreview = null, // color boxes above the radio buttons
            currentPreview = null,
            okButton = null,
            cancelButton = null,
            grid = null, // preset colors grid
            iconColor = null, // iconColor for popup icon
            iconAlpha = null, // iconAlpha for popup icon
            iconImage = null, // iconImage popup icon
            moveBar = null, // drag bar
            setColorMode = // set color mode and update visuals for the new color mode
              function (colorMode) {
                  var active = color.active, // local copies for YUI compressor
                  clientPath = images.clientPath,
                  hex = active.val('hex'),
                  rgbMap,
                  rgbBar;
                  settings.color.mode = colorMode;
                  switch (colorMode) {
                      case 'h':
                          setTimeout(
                      function () {
                          setBG.call($this, colorMapDiv, 'transparent');
                          setImgLoc.call($this, colorMapL1, 0);
                          setAlpha.call($this, colorMapL1, 100);
                          setImgLoc.call($this, colorMapL2, 260);
                          setAlpha.call($this, colorMapL2, 100);
                          setBG.call($this, colorBarDiv, 'transparent');
                          setImgLoc.call($this, colorBarL1, 0);
                          setAlpha.call($this, colorBarL1, 100);
                          setImgLoc.call($this, colorBarL2, 260);
                          setAlpha.call($this, colorBarL2, 100);
                          setImgLoc.call($this, colorBarL3, 260);
                          setAlpha.call($this, colorBarL3, 100);
                          setImgLoc.call($this, colorBarL4, 260);
                          setAlpha.call($this, colorBarL4, 100);
                          setImgLoc.call($this, colorBarL6, 260);
                          setAlpha.call($this, colorBarL6, 100);
                      }, 0);
                          colorMap.range('all', { minX: 0, maxX: 100, minY: 0, maxY: 100 });
                          colorBar.range('rangeY', { minY: 0, maxY: 360 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('s'), y: 100 - active.val('v') }, colorMap);
                          colorBar.val('y', 360 - active.val('h'), colorBar);
                          break;
                      case 's':
                          setTimeout(
                      function () {
                          setBG.call($this, colorMapDiv, 'transparent');
                          setImgLoc.call($this, colorMapL1, -260);
                          setImgLoc.call($this, colorMapL2, -520);
                          setImgLoc.call($this, colorBarL1, -260);
                          setImgLoc.call($this, colorBarL2, -520);
                          setImgLoc.call($this, colorBarL6, 260);
                          setAlpha.call($this, colorBarL6, 100);
                      }, 0);
                          colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 });
                          colorBar.range('rangeY', { minY: 0, maxY: 100 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('v') }, colorMap);
                          colorBar.val('y', 100 - active.val('s'), colorBar);
                          break;
                      case 'v':
                          setTimeout(
                      function () {
                          setBG.call($this, colorMapDiv, '000000');
                          setImgLoc.call($this, colorMapL1, -780);
                          setImgLoc.call($this, colorMapL2, 260);
                          setBG.call($this, colorBarDiv, hex);
                          setImgLoc.call($this, colorBarL1, -520);
                          setImgLoc.call($this, colorBarL2, 260);
                          setAlpha.call($this, colorBarL2, 100);
                          setImgLoc.call($this, colorBarL6, 260);
                          setAlpha.call($this, colorBarL6, 100);
                      }, 0);
                          colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 });
                          colorBar.range('rangeY', { minY: 0, maxY: 100 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('s') }, colorMap);
                          colorBar.val('y', 100 - active.val('v'), colorBar);
                          break;
                      case 'r':
                          rgbMap = -1040;
                          rgbBar = -780;
                          colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 });
                          colorBar.range('rangeY', { minY: 0, maxY: 255 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('b'), y: 255 - active.val('g') }, colorMap);
                          colorBar.val('y', 255 - active.val('r'), colorBar);
                          break;
                      case 'g':
                          rgbMap = -1560;
                          rgbBar = -1820;
                          colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 });
                          colorBar.range('rangeY', { minY: 0, maxY: 255 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('b'), y: 255 - active.val('r') }, colorMap);
                          colorBar.val('y', 255 - active.val('g'), colorBar);
                          break;
                      case 'b':
                          rgbMap = -2080;
                          rgbBar = -2860;
                          colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 });
                          colorBar.range('rangeY', { minY: 0, maxY: 255 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('r'), y: 255 - active.val('g') }, colorMap);
                          colorBar.val('y', 255 - active.val('b'), colorBar);
                          break;
                      case 'a':
                          setTimeout(
                      function () {
                          setBG.call($this, colorMapDiv, 'transparent');
                          setImgLoc.call($this, colorMapL1, -260);
                          setImgLoc.call($this, colorMapL2, -520);
                          setImgLoc.call($this, colorBarL1, 260);
                          setImgLoc.call($this, colorBarL2, 260);
                          setAlpha.call($this, colorBarL2, 100);
                          setImgLoc.call($this, colorBarL6, 0);
                          setAlpha.call($this, colorBarL6, 100);
                      }, 0);
                          colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 });
                          colorBar.range('rangeY', { minY: 0, maxY: 255 });
                          if (active.val('ahex') == null) break;
                          colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('v') }, colorMap);
                          colorBar.val('y', 255 - active.val('a'), colorBar);
                          break;
                      default:
                          throw ('Invalid Mode');
                          break;
                  }
                  switch (colorMode) {
                      case 'h':
                          break;
                      case 's':
                      case 'v':
                      case 'a':
                          setTimeout(
                      function () {
                          setAlpha.call($this, colorMapL1, 100);
                          setAlpha.call($this, colorBarL1, 100);
                          setImgLoc.call($this, colorBarL3, 260);
                          setAlpha.call($this, colorBarL3, 100);
                          setImgLoc.call($this, colorBarL4, 260);
                          setAlpha.call($this, colorBarL4, 100);
                      }, 0);
                          break;
                      case 'r':
                      case 'g':
                      case 'b':
                          setTimeout(
                      function () {
                          setBG.call($this, colorMapDiv, 'transparent');
                          setBG.call($this, colorBarDiv, 'transparent');
                          setAlpha.call($this, colorBarL1, 100);
                          setAlpha.call($this, colorMapL1, 100);
                          setImgLoc.call($this, colorMapL1, rgbMap);
                          setImgLoc.call($this, colorMapL2, rgbMap - 260);
                          setImgLoc.call($this, colorBarL1, rgbBar - 780);
                          setImgLoc.call($this, colorBarL2, rgbBar - 520);
                          setImgLoc.call($this, colorBarL3, rgbBar);
                          setImgLoc.call($this, colorBarL4, rgbBar - 260);
                          setImgLoc.call($this, colorBarL6, 260);
                          setAlpha.call($this, colorBarL6, 100);
                      }, 0);
                          break;
                  }
                  if (active.val('ahex') == null) return;
                  activeColorChanged.call($this, active);
              },
            activeColorChanged = // Update color when user changes text values
              function (ui, context) {
                  if (context == null || (context != colorBar && context != colorMap)) positionMapAndBarArrows.call($this, ui, context);
                  setTimeout(
                  function () {
                      updatePreview.call($this, ui);
                      updateMapVisuals.call($this, ui);
                      updateBarVisuals.call($this, ui);
                  }, 0);
              },
            mapValueChanged = // user has dragged the ColorMap pointer
              function (ui, context) {
                  var active = color.active;
                  if (context != colorMap && active.val() == null) return;
                  var xy = ui.val('all');
                  switch (settings.color.mode) {
                      case 'h':
                          active.val('sv', { s: xy.x, v: 100 - xy.y }, context);
                          break;
                      case 's':
                      case 'a':
                          active.val('hv', { h: xy.x, v: 100 - xy.y }, context);
                          break;
                      case 'v':
                          active.val('hs', { h: xy.x, s: 100 - xy.y }, context);
                          break;
                      case 'r':
                          active.val('gb', { g: 255 - xy.y, b: xy.x }, context);
                          break;
                      case 'g':
                          active.val('rb', { r: 255 - xy.y, b: xy.x }, context);
                          break;
                      case 'b':
                          active.val('rg', { r: xy.x, g: 255 - xy.y }, context);
                          break;
                  }
              },
            colorBarValueChanged = // user has dragged the ColorBar slider
              function (ui, context) {
                  var active = color.active;
                  if (context != colorBar && active.val() == null) return;
                  switch (settings.color.mode) {
                      case 'h':
                          active.val('h', { h: 360 - ui.val('y') }, context);
                          break;
                      case 's':
                          active.val('s', { s: 100 - ui.val('y') }, context);
                          break;
                      case 'v':
                          active.val('v', { v: 100 - ui.val('y') }, context);
                          break;
                      case 'r':
                          active.val('r', { r: 255 - ui.val('y') }, context);
                          break;
                      case 'g':
                          active.val('g', { g: 255 - ui.val('y') }, context);
                          break;
                      case 'b':
                          active.val('b', { b: 255 - ui.val('y') }, context);
                          break;
                      case 'a':
                          active.val('a', 255 - ui.val('y'), context);
                          break;
                  }
              },
            positionMapAndBarArrows = // position map and bar arrows to match current color
              function (ui, context) {
                  if (context != colorMap) {
                      switch (settings.color.mode) {
                          case 'h':
                              var sv = ui.val('sv');
                              colorMap.val('xy', { x: sv != null ? sv.s : 100, y: 100 - (sv != null ? sv.v : 100) }, context);
                              break;
                          case 's':
                          case 'a':
                              var hv = ui.val('hv');
                              colorMap.val('xy', { x: hv && hv.h || 0, y: 100 - (hv != null ? hv.v : 100) }, context);
                              break;
                          case 'v':
                              var hs = ui.val('hs');
                              colorMap.val('xy', { x: hs && hs.h || 0, y: 100 - (hs != null ? hs.s : 100) }, context);
                              break;
                          case 'r':
                              var bg = ui.val('bg');
                              colorMap.val('xy', { x: bg && bg.b || 0, y: 255 - (bg && bg.g || 0) }, context);
                              break;
                          case 'g':
                              var br = ui.val('br');
                              colorMap.val('xy', { x: br && br.b || 0, y: 255 - (br && br.r || 0) }, context);
                              break;
                          case 'b':
                              var rg = ui.val('rg');
                              colorMap.val('xy', { x: rg && rg.r || 0, y: 255 - (rg && rg.g || 0) }, context);
                              break;
                      }
                  }
                  if (context != colorBar) {
                      switch (settings.color.mode) {
                          case 'h':
                              colorBar.val('y', 360 - (ui.val('h') || 0), context);
                              break;
                          case 's':
                              var s = ui.val('s');
                              colorBar.val('y', 100 - (s != null ? s : 100), context);
                              break;
                          case 'v':
                              var v = ui.val('v');
                              colorBar.val('y', 100 - (v != null ? v : 100), context);
                              break;
                          case 'r':
                              colorBar.val('y', 255 - (ui.val('r') || 0), context);
                              break;
                          case 'g':
                              colorBar.val('y', 255 - (ui.val('g') || 0), context);
                              break;
                          case 'b':
                              colorBar.val('y', 255 - (ui.val('b') || 0), context);
                              break;
                          case 'a':
                              var a = ui.val('a');
                              colorBar.val('y', 255 - (a != null ? a : 255), context);
                              break;
                      }
                  }
              },
            updatePreview =
              function (ui) {
                  try {
                      var all = ui.val('all');
                      activePreview.css({ backgroundColor: all && '#' + all.hex || 'transparent' });
                      setAlpha.call($this, activePreview, all && Math.precision((all.a * 100) / 255, 4) || 0);
                  }
                  catch (e) { }
              },
            updateMapVisuals =
              function (ui) {
                  switch (settings.color.mode) {
                      case 'h':
                          setBG.call($this, colorMapDiv, new Color({ h: ui.val('h') || 0, s: 100, v: 100 }).val('hex'));
                          break;
                      case 's':
                      case 'a':
                          var s = ui.val('s');
                          setAlpha.call($this, colorMapL2, 100 - (s != null ? s : 100));
                          break;
                      case 'v':
                          var v = ui.val('v');
                          setAlpha.call($this, colorMapL1, v != null ? v : 100);
                          break;
                      case 'r':
                          setAlpha.call($this, colorMapL2, Math.precision((ui.val('r') || 0) / 255 * 100, 4));
                          break;
                      case 'g':
                          setAlpha.call($this, colorMapL2, Math.precision((ui.val('g') || 0) / 255 * 100, 4));
                          break;
                      case 'b':
                          setAlpha.call($this, colorMapL2, Math.precision((ui.val('b') || 0) / 255 * 100));
                          break;
                  }
                  var a = ui.val('a');
                  setAlpha.call($this, colorMapL3, Math.precision(((255 - (a || 0)) * 100) / 255, 4));
              },
            updateBarVisuals =
              function (ui) {
                  switch (settings.color.mode) {
                      case 'h':
                          var a = ui.val('a');
                          setAlpha.call($this, colorBarL5, Math.precision(((255 - (a || 0)) * 100) / 255, 4));
                          break;
                      case 's':
                          var hva = ui.val('hva'),
                        saturatedColor = new Color({ h: hva && hva.h || 0, s: 100, v: hva != null ? hva.v : 100 });
                          setBG.call($this, colorBarDiv, saturatedColor.val('hex'));
                          setAlpha.call($this, colorBarL2, 100 - (hva != null ? hva.v : 100));
                          setAlpha.call($this, colorBarL5, Math.precision(((255 - (hva && hva.a || 0)) * 100) / 255, 4));
                          break;
                      case 'v':
                          var hsa = ui.val('hsa'),
                        valueColor = new Color({ h: hsa && hsa.h || 0, s: hsa != null ? hsa.s : 100, v: 100 });
                          setBG.call($this, colorBarDiv, valueColor.val('hex'));
                          setAlpha.call($this, colorBarL5, Math.precision(((255 - (hsa && hsa.a || 0)) * 100) / 255, 4));
                          break;
                      case 'r':
                      case 'g':
                      case 'b':
                          var hValue = 0, vValue = 0, rgba = ui.val('rgba');
                          if (settings.color.mode == 'r') {
                              hValue = rgba && rgba.b || 0;
                              vValue = rgba && rgba.g || 0;
                          }
                          else if (settings.color.mode == 'g') {
                              hValue = rgba && rgba.b || 0;
                              vValue = rgba && rgba.r || 0;
                          }
                          else if (settings.color.mode == 'b') {
                              hValue = rgba && rgba.r || 0;
                              vValue = rgba && rgba.g || 0;
                          }
                          var middle = vValue > hValue ? hValue : vValue;
                          setAlpha.call($this, colorBarL2, hValue > vValue ? Math.precision(((hValue - vValue) / (255 - vValue)) * 100, 4) : 0);
                          setAlpha.call($this, colorBarL3, vValue > hValue ? Math.precision(((vValue - hValue) / (255 - hValue)) * 100, 4) : 0);
                          setAlpha.call($this, colorBarL4, Math.precision((middle / 255) * 100, 4));
                          setAlpha.call($this, colorBarL5, Math.precision(((255 - (rgba && rgba.a || 0)) * 100) / 255, 4));
                          break;
                      case 'a':
                          var a = ui.val('a');
                          setBG.call($this, colorBarDiv, ui.val('hex') || '000000');
                          setAlpha.call($this, colorBarL5, a != null ? 0 : 100);
                          setAlpha.call($this, colorBarL6, a != null ? 100 : 0);
                          break;
                  }
              },
            setBG =
              function (el, c) {
                  el.css({ backgroundColor: c && c.length == 6 && '#' + c || 'transparent' });
              },
            setImg =
              function (img, src) {
                  if (isLessThanIE7 && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) {
                      img.attr('pngSrc', src);
                      img.css({ backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' });
                  }
                  else img.css({ backgroundImage: 'url(\'' + src + '\')' });
              },
            setImgLoc =
              function (img, y) {
                  img.css({ top: y + 'px' });
              },
            setAlpha =
              function (obj, alpha) {
                  obj.css({ visibility: alpha > 0 ? 'visible' : 'hidden' });
                  if (alpha > 0 && alpha < 100) {
                      if (isLessThanIE7) {
                          var src = obj.attr('pngSrc');
                          if (src != null && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1))
                              obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\') progid:DXImageTransform.Microsoft.Alpha(opacity=' + alpha + ')' });
                          else obj.css({ opacity: Math.precision(alpha / 100, 4) });
                      }
                      else obj.css({ opacity: Math.precision(alpha / 100, 4) });
                  }
                  else if (alpha == 0 || alpha == 100) {
                      if (isLessThanIE7) {
                          var src = obj.attr('pngSrc');
                          if (src != null && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1))
                              obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' });
                          else obj.css({ opacity: '' });
                      }
                      else obj.css({ opacity: '' });
                  }
              },
            revertColor = // revert color to original color when opened
              function () {
                  color.active.val('ahex', color.current.val('ahex'));
              },
            commitColor = // commit the color changes
              function () {
                  color.current.val('ahex', color.active.val('ahex'));
              },
            radioClicked =
              function (e) {
                  $(this).parents('tbody:first').find('input:radio[value!="' + e.target.value + '"]').removeAttr('checked');
                  setColorMode.call($this, e.target.value);
              },
            currentClicked =
              function () {
                  revertColor.call($this);
              },
            cancelClicked =
              function () {
                  revertColor.call($this);
                  settings.window.expandable && hide.call($this);
                  $.isFunction(cancelCallback) && cancelCallback.call($this, color.active, cancelButton);
              },
            okClicked =
              function () {
                  commitColor.call($this);
                  settings.window.expandable && hide.call($this);
                  $.isFunction(commitCallback) && commitCallback.call($this, color.active, okButton);
              },
            iconImageClicked =
              function () {
                  show.call($this);
              },
            currentColorChanged =
              function (ui, context) {
                  var hex = ui.val('hex');
                  currentPreview.css({ backgroundColor: hex && '#' + hex || 'transparent' });
                  setAlpha.call($this, currentPreview, Math.precision(((ui.val('a') || 0) * 100) / 255, 4));
              },
            expandableColorChanged =
              function (ui, context) {
                  var hex = ui.val('hex');
                  var va = ui.val('va');
                  iconColor.css({ backgroundColor: hex && '#' + hex || 'transparent' });
                  setAlpha.call($this, iconAlpha, Math.precision(((255 - (va && va.a || 0)) * 100) / 255, 4));
                  if (settings.window.bindToInput && settings.window.updateInputColor)
                      settings.window.input.css(
                    {
                        backgroundColor: hex && '#' + hex || 'transparent',
                        color: va == null || va.v > 75 ? '#000000' : '#ffffff'
                    });
              },
            moveBarMouseDown =
              function (e) {
                  var element = settings.window.element, // local copies for YUI compressor
                  page = settings.window.page;
                  elementStartX = parseInt(container.css('left'));
                  elementStartY = parseInt(container.css('top'));
                  pageStartX = e.pageX;
                  pageStartY = e.pageY;
                  // bind events to document to move window - we will unbind these on mouseup
                  $(document).bind('mousemove', documentMouseMove).bind('mouseup', documentMouseUp);
                  e.preventDefault(); // prevent attempted dragging of the column
              },
            documentMouseMove =
              function (e) {
                  container.css({ left: elementStartX - (pageStartX - e.pageX) + 'px', top: elementStartY - (pageStartY - e.pageY) + 'px' });
                  if (settings.window.expandable && !$.support.boxModel) container.prev().css({ left: container.css("left"), top: container.css("top") });
                  e.stopPropagation();
                  e.preventDefault();
                  return false;
              },
            documentMouseUp =
              function (e) {
                  $(document).unbind('mousemove', documentMouseMove).unbind('mouseup', documentMouseUp);
                  e.stopPropagation();
                  e.preventDefault();
                  return false;
              },
            quickPickClicked =
              function (e) {
                  e.preventDefault();
                  e.stopPropagation();
                  color.active.val('ahex', $(this).attr('title') || null, e.target);
                  return false;
              },
            commitCallback = $.isFunction($arguments[1]) && $arguments[1] || null,
            liveCallback = $.isFunction($arguments[2]) && $arguments[2] || null,
            cancelCallback = $.isFunction($arguments[3]) && $arguments[3] || null,
            show =
              function () {
                  color.current.val('ahex', color.active.val('ahex'));
                  var attachIFrame = function () {
                      if (!settings.window.expandable || $.support.boxModel) return;
                      var table = container.find('table:first');
                      container.before('<iframe/>');
                      container.prev().css({ width: table.width(), height: container.height(), opacity: 0, position: 'absolute', left: container.css("left"), top: container.css("top") });
                  };
                  if (settings.window.expandable) {
                      $(document.body).children('div.jPicker.Container').css({ zIndex: 10 });
                      container.css({ zIndex: zIndexNewValue });
                  }
                  switch (settings.window.effects.type) {
                      case 'fade':
                          container.fadeIn(settings.window.effects.speed.show, attachIFrame);
                          break;
                      case 'slide':
                          container.slideDown(settings.window.effects.speed.show, attachIFrame);
                          break;
                      case 'show':
                      default:
                          container.show(settings.window.effects.speed.show, attachIFrame);
                          break;
                  }
              },
            hide =
              function () {
                  var removeIFrame = function () {
                      if (settings.window.expandable) container.css({ zIndex: 10 });
                      if (!settings.window.expandable || $.support.boxModel) return;
                      container.prev().remove();
                  };
                  switch (settings.window.effects.type) {
                      case 'fade':
                          container.fadeOut(settings.window.effects.speed.hide, removeIFrame);
                          break;
                      case 'slide':
                          container.slideUp(settings.window.effects.speed.hide, removeIFrame);
                          break;
                      case 'show':
                      default:
                          container.hide(settings.window.effects.speed.hide, removeIFrame);
                          break;
                  }
              },
            initialize =
              function () {
                  var win = settings.window,
                    popup = win.expandable ? $($this).next().find('.Container:first') : null;
                  container = win.expandable ? $('<div/>') : $($this);
                  container.addClass('jPicker Container');
                  if (win.expandable) container.hide();
                  container.get(0).onselectstart = function (event) { if (event.target.nodeName.toLowerCase() !== 'input') return false; };
                  // inject html source code - we are using a single table for this control - I know tables are considered bad, but it takes care of equal height columns and
                  // this control really is tabular data, so I believe it is the right move
                  var all = color.active.val('all');
                  if (win.alphaPrecision < 0) win.alphaPrecision = 0;
                  else if (win.alphaPrecision > 2) win.alphaPrecision = 2;
                  var controlHtml = '<table class="jPicker" cellpadding="0" cellspacing="0"><tbody>' + (win.expandable ? '<tr><td class="Move" colspan="5">&nbsp;</td></tr>' : '') + '<tr><td rowspan="9"><h2 class="Title">' + (win.title || localization.text.title) + '</h2><div class="Map"><span class="Map1">&nbsp;</span><span class="Map2">&nbsp;</span><span class="Map3">&nbsp;</span><img src="' + images.clientPath + images.colorMap.arrow.file + '" class="Arrow"/></div></td><td rowspan="9"><div class="Bar"><span class="Map1">&nbsp;</span><span class="Map2">&nbsp;</span><span class="Map3">&nbsp;</span><span class="Map4">&nbsp;</span><span class="Map5">&nbsp;</span><span class="Map6">&nbsp;</span><img src="' + images.clientPath + images.colorBar.arrow.file + '" class="Arrow"/></div></td><td colspan="2" class="Preview">' + localization.text.newColor + '<div><span class="Active" title="' + localization.tooltips.colors.newColor + '">&nbsp;</span><span class="Current" title="' + localization.tooltips.colors.currentColor + '">&nbsp;</span></div>' + localization.text.currentColor + '</td><td rowspan="9" class="Button"><input type="button" class="Ok" value="' + localization.text.ok + '" title="' + localization.tooltips.buttons.ok + '"/><input type="button" class="Cancel" value="' + localization.text.cancel + '" title="' + localization.tooltips.buttons.cancel + '"/><hr/><div class="Grid">&nbsp;</div></td></tr><tr class="Hue"><td class="Radio"><label title="' + localization.tooltips.hue.radio + '"><input type="radio" value="h"' + (settings.color.mode == 'h' ? ' checked="checked"' : '') + '/>H:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.h : '') + '" title="' + localization.tooltips.hue.textbox + '"/>&nbsp;&deg;</td></tr><tr class="Saturation"><td class="Radio"><label title="' + localization.tooltips.saturation.radio + '"><input type="radio" value="s"' + (settings.color.mode == 's' ? ' checked="checked"' : '') + '/>S:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.s : '') + '" title="' + localization.tooltips.saturation.textbox + '"/>&nbsp;%</td></tr><tr class="Value"><td class="Radio"><label title="' + localization.tooltips.value.radio + '"><input type="radio" value="v"' + (settings.color.mode == 'v' ? ' checked="checked"' : '') + '/>V:</label><br/><br/></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.v : '') + '" title="' + localization.tooltips.value.textbox + '"/>&nbsp;%<br/><br/></td></tr><tr class="Red"><td class="Radio"><label title="' + localization.tooltips.red.radio + '"><input type="radio" value="r"' + (settings.color.mode == 'r' ? ' checked="checked"' : '') + '/>R:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.r : '') + '" title="' + localization.tooltips.red.textbox + '"/></td></tr><tr class="Green"><td class="Radio"><label title="' + localization.tooltips.green.radio + '"><input type="radio" value="g"' + (settings.color.mode == 'g' ? ' checked="checked"' : '') + '/>G:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.g : '') + '" title="' + localization.tooltips.green.textbox + '"/></td></tr><tr class="Blue"><td class="Radio"><label title="' + localization.tooltips.blue.radio + '"><input type="radio" value="b"' + (settings.color.mode == 'b' ? ' checked="checked"' : '') + '/>B:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.b : '') + '" title="' + localization.tooltips.blue.textbox + '"/></td></tr><tr class="Alpha"><td class="Radio">' + (win.alphaSupport ? '<label title="' + localization.tooltips.alpha.radio + '"><input type="radio" value="a"' + (settings.color.mode == 'a' ? ' checked="checked"' : '') + '/>A:</label>' : '&nbsp;') + '</td><td class="Text">' + (win.alphaSupport ? '<input type="text" maxlength="' + (3 + win.alphaPrecision) + '" value="' + (all != null ? Math.precision((all.a * 100) / 255, win.alphaPrecision) : '') + '" title="' + localization.tooltips.alpha.textbox + '"/>&nbsp;%' : '&nbsp;') + '</td></tr><tr class="Hex"><td colspan="2" class="Text"><label title="' + localization.tooltips.hex.textbox + '">#:<input type="text" maxlength="6" class="Hex" value="' + (all != null ? all.hex : '') + '"/></label>' + (win.alphaSupport ? '<input type="text" maxlength="2" class="AHex" value="' + (all != null ? all.ahex.substring(6) : '') + '" title="' + localization.tooltips.hex.alpha + '"/></td>' : '&nbsp;') + '</tr></tbody></table>';
                  if (win.expandable) {
                      container.html(controlHtml);
                      if ($(document.body).children('div.jPicker.Container').length == 0) $(document.body).prepend(container);
                      else $(document.body).children('div.jPicker.Container:last').after(container);
                      container.mousedown(
                    function () {
                        $(document.body).children('div.jPicker.Container').css({ zIndex: 10 });
                        container.css({ zIndex: zIndexNewValue });
                    });
                      container.css( // positions must be set and display set to absolute before source code injection or IE will size the container to fit the window
                    {
                    left:
                        win.position.x == 'left' ? (popup.offset().left - 530 - (win.position.y == 'center' ? 25 : 0)) + 'px' :
                        win.position.x == 'center' ? (popup.offset().left - 260) + 'px' :
                        win.position.x == 'right' ? (popup.offset().left - 10 + (win.position.y == 'center' ? 25 : 0)) + 'px' :
                        win.position.x == 'screenCenter' ? (($(document).width() >> 1) - 260) + 'px' : (popup.offset().left + parseInt(win.position.x)) + 'px',
                    position: 'absolute',
                    top: win.position.y == 'top' ? (popup.offset().top - 312) + 'px' :
                           win.position.y == 'center' ? (popup.offset().top - 156) + 'px' :
                           win.position.y == 'bottom' ? (popup.offset().top + 25) + 'px' : (popup.offset().top + parseInt(win.position.y)) + 'px'
                });
                  }
                  else {
                      container = $($this);
                      container.html(controlHtml);
                  }
                  // initialize the objects to the source code just injected
                  var tbody = container.find('tbody:first');
                  colorMapDiv = tbody.find('div.Map:first');
                  colorBarDiv = tbody.find('div.Bar:first');
                  var MapMaps = colorMapDiv.find('span'),
                    BarMaps = colorBarDiv.find('span');
                  colorMapL1 = MapMaps.filter('.Map1:first');
                  colorMapL2 = MapMaps.filter('.Map2:first');
                  colorMapL3 = MapMaps.filter('.Map3:first');
                  colorBarL1 = BarMaps.filter('.Map1:first');
                  colorBarL2 = BarMaps.filter('.Map2:first');
                  colorBarL3 = BarMaps.filter('.Map3:first');
                  colorBarL4 = BarMaps.filter('.Map4:first');
                  colorBarL5 = BarMaps.filter('.Map5:first');
                  colorBarL6 = BarMaps.filter('.Map6:first');
                  // create color pickers and maps
                  colorMap = new Slider(colorMapDiv,
                  {
                      map:
                    {
                        width: images.colorMap.width,
                        height: images.colorMap.height
                    },
                      arrow:
                    {
                        image: images.clientPath + images.colorMap.arrow.file,
                        width: images.colorMap.arrow.width,
                        height: images.colorMap.arrow.height
                    }
                  });
                  colorMap.bind(mapValueChanged);
                  colorBar = new Slider(colorBarDiv,
                  {
                      map:
                    {
                        width: images.colorBar.width,
                        height: images.colorBar.height
                    },
                      arrow:
                    {
                        image: images.clientPath + images.colorBar.arrow.file,
                        width: images.colorBar.arrow.width,
                        height: images.colorBar.arrow.height
                    }
                  });
                  colorBar.bind(colorBarValueChanged);
                  colorPicker = new ColorValuePicker(tbody, color.active, win.expandable && win.bindToInput ? win.input : null, win.alphaPrecision);
                  var hex = all != null ? all.hex : null,
                    preview = tbody.find('.Preview'),
                    button = tbody.find('.Button');
                  activePreview = preview.find('.Active:first').css({ backgroundColor: hex && '#' + hex || 'transparent' });
                  currentPreview = preview.find('.Current:first').css({ backgroundColor: hex && '#' + hex || 'transparent' }).bind('click', currentClicked);
                  setAlpha.call($this, currentPreview, Math.precision(color.current.val('a') * 100) / 255, 4);
                  okButton = button.find('.Ok:first').bind('click', okClicked);
                  cancelButton = button.find('.Cancel:first').bind('click', cancelClicked);
                  grid = button.find('.Grid:first');
                  setTimeout(
                  function () {
                      setImg.call($this, colorMapL1, images.clientPath + 'Maps.png');
                      setImg.call($this, colorMapL2, images.clientPath + 'Maps.png');
                      setImg.call($this, colorMapL3, images.clientPath + 'map-opacity.png');
                      setImg.call($this, colorBarL1, images.clientPath + 'Bars.png');
                      setImg.call($this, colorBarL2, images.clientPath + 'Bars.png');
                      setImg.call($this, colorBarL3, images.clientPath + 'Bars.png');
                      setImg.call($this, colorBarL4, images.clientPath + 'Bars.png');
                      setImg.call($this, colorBarL5, images.clientPath + 'bar-opacity.png');
                      setImg.call($this, colorBarL6, images.clientPath + 'AlphaBar.png');
                      setImg.call($this, preview.find('div:first'), images.clientPath + 'preview-opacity.png');
                  }, 0);
                  tbody.find('td.Radio input').bind('click', radioClicked);
                  // initialize quick list
                  if (color.quickList && color.quickList.length > 0) {
                      var html = '';
                      for (i = 0; i < color.quickList.length; i++) {
                          /* if default colors are hex strings, change them to color objects */
                          if ((typeof (color.quickList[i])).toString().toLowerCase() == 'string') color.quickList[i] = new Color({ hex: color.quickList[i] });
                          var alpha = color.quickList[i].val('a');
                          var ahex = color.quickList[i].val('ahex');
                          if (!win.alphaSupport && ahex) ahex = ahex.substring(0, 6) + 'ff';
                          var quickHex = color.quickList[i].val('hex');
                          html += '<span class="QuickColor"' + (ahex && ' title="#' + ahex + '"' || '') + ' style="background-color:' + (quickHex && '#' + quickHex || '') + ';' + (quickHex ? '' : 'background-image:url(' + images.clientPath + 'NoColor.png)') + (win.alphaSupport && alpha && alpha < 255 ? ';opacity:' + Math.precision(alpha / 255, 4) + ';filter:Alpha(opacity=' + Math.precision(alpha / 2.55, 4) + ')' : '') + '">&nbsp;</span>';
                      }
                      setImg.call($this, grid, images.clientPath + 'bar-opacity.png');
                      grid.html(html);
                      grid.find('.QuickColor').click(quickPickClicked);
                  }
                  setColorMode.call($this, settings.color.mode);
                  color.active.bind(activeColorChanged);
                  $.isFunction(liveCallback) && color.active.bind(liveCallback);
                  color.current.bind(currentColorChanged);
                  // bind to input
                  if (win.expandable) {
                      $this.icon = popup.parents('.Icon:first');
                      iconColor = $this.icon.find('.Color:first').css({ backgroundColor: hex && '#' + hex || 'transparent' });
                      iconAlpha = $this.icon.find('.Alpha:first');
                      setImg.call($this, iconAlpha, images.clientPath + 'bar-opacity.png');
                      setAlpha.call($this, iconAlpha, Math.precision(((255 - (all != null ? all.a : 0)) * 100) / 255, 4));
                      iconImage = $this.icon.find('.Image:first').css(
                    {
                        backgroundImage: 'url(\'' + images.clientPath + images.picker.file + '\')'
                    }).bind('click', iconImageClicked);
                      if (win.bindToInput && win.updateInputColor)
                          win.input.css(
                      {
                          backgroundColor: hex && '#' + hex || 'transparent',
                          color: all == null || all.v > 75 ? '#000000' : '#ffffff'
                      });
                      moveBar = tbody.find('.Move:first').bind('mousedown', moveBarMouseDown);
                      color.active.bind(expandableColorChanged);
                  }
                  else show.call($this);
              },
            destroy =
              function () {
                  container.find('td.Radio input').unbind('click', radioClicked);
                  currentPreview.unbind('click', currentClicked);
                  cancelButton.unbind('click', cancelClicked);
                  okButton.unbind('click', okClicked);
                  if (settings.window.expandable) {
                      iconImage.unbind('click', iconImageClicked);
                      moveBar.unbind('mousedown', moveBarMouseDown);
                      $this.icon = null;
                  }
                  container.find('.QuickColor').unbind('click', quickPickClicked);
                  colorMapDiv = null;
                  colorBarDiv = null;
                  colorMapL1 = null;
                  colorMapL2 = null;
                  colorMapL3 = null;
                  colorBarL1 = null;
                  colorBarL2 = null;
                  colorBarL3 = null;
                  colorBarL4 = null;
                  colorBarL5 = null;
                  colorBarL6 = null;
                  colorMap.destroy();
                  colorMap = null;
                  colorBar.destroy();
                  colorBar = null;
                  colorPicker.destroy();
                  colorPicker = null;
                  activePreview = null;
                  currentPreview = null;
                  okButton = null;
                  cancelButton = null;
                  grid = null;
                  commitCallback = null;
                  cancelCallback = null;
                  liveCallback = null;
                  container.html('');
                  for (i = 0; i < List.length; i++) if (List[i] == $this) List.splice(i, 1);
              },
            images = settings.images, // local copies for YUI compressor
            localization = settings.localization,
            color =
              {
                  active: (typeof (settings.color.active)).toString().toLowerCase() == 'string' ? new Color({ ahex: !settings.window.alphaSupport && settings.color.active ? settings.color.active.substring(0, 6) + 'ff' : settings.color.active }) : new Color({ ahex: !settings.window.alphaSupport && settings.color.active.val('ahex') ? settings.color.active.val('ahex').substring(0, 6) + 'ff' : settings.color.active.val('ahex') }),
                  current: (typeof (settings.color.active)).toString().toLowerCase() == 'string' ? new Color({ ahex: !settings.window.alphaSupport && settings.color.active ? settings.color.active.substring(0, 6) + 'ff' : settings.color.active }) : new Color({ ahex: !settings.window.alphaSupport && settings.color.active.val('ahex') ? settings.color.active.val('ahex').substring(0, 6) + 'ff' : settings.color.active.val('ahex') }),
                  quickList: settings.color.quickList
              };
            $.extend(true, $this, // public properties, methods, and callbacks
            {
            commitCallback: commitCallback, // commitCallback function can be overridden to return the selected color to a method you specify when the user clicks "OK"
            liveCallback: liveCallback, // liveCallback function can be overridden to return the selected color to a method you specify in live mode (continuous update)
            cancelCallback: cancelCallback, // cancelCallback function can be overridden to a method you specify when the user clicks "Cancel"
            color: color,
            show: show,
            hide: hide,
            destroy: destroy // destroys this control entirely, removing all events and objects, and removing itself from the List
        });
        List.push($this);
        setTimeout(
            function () {
                initialize.call($this);
            }, 0);
    });
};
$.fn.jPicker.defaults = /* jPicker defaults - you can change anything in this section (such as the clientPath to your images) without fear of breaking the program */
      {
      window:
        {
            title: null, /* any title for the jPicker window itself - displays "Drag Markers To Pick A Color" if left null */
            effects:
          {
              type: 'slide', /* effect used to show/hide an expandable picker. Acceptable values "slide", "show", "fade" */
              speed:
            {
                show: 'slow', /* duration of "show" effect. Acceptable values are "fast", "slow", or time in ms */
                hide: 'fast' /* duration of "hide" effect. Acceptable values are "fast", "slow", or time in ms */
            }
          },
            position:
          {
              x: 'screenCenter', /* acceptable values "left", "center", "right", "screenCenter", or relative px value */
              y: 'top' /* acceptable values "top", "bottom", "center", or relative px value */
          },
            expandable: false, /* default to large static picker - set to true to make an expandable picker (small icon with popup) - set automatically when binded to input element */
            liveUpdate: true, /* set false if you want the user to have to click "OK" before the binded input box updates values (always "true" for expandable picker) */
            alphaSupport: false, /* set to true to enable alpha picking */
            alphaPrecision: 0, /* set decimal precision for alpha percentage display - hex codes do not map directly to percentage integers - range 0-2 */
            updateInputColor: true /* set to false to prevent binded input colors from changing */
        },
      color:
        {
            mode: 'h', /* acceptabled values "h" (hue), "s" (saturation), "v" (value), "r" (red), "g" (green), "b" (blue), "a" (alpha) */
            active: new Color({ ahex: '#ffcc00ff' }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) WITH OR WITHOUT the "#" prefix */
            quickList: /* the quick pick color list */
            [
              new Color({ h: 360, s: 33, v: 100 }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) WITH OR WITHOUT the "#" prefix */
              new Color({ h: 360, s: 66, v: 100 }),
              new Color({ h: 360, s: 100, v: 100 }),
              new Color({ h: 360, s: 100, v: 75 }),
              new Color({ h: 360, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 100 }),
              new Color({ h: 30, s: 33, v: 100 }),
              new Color({ h: 30, s: 66, v: 100 }),
              new Color({ h: 30, s: 100, v: 100 }),
              new Color({ h: 30, s: 100, v: 75 }),
              new Color({ h: 30, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 90 }),
              new Color({ h: 60, s: 33, v: 100 }),
              new Color({ h: 60, s: 66, v: 100 }),
              new Color({ h: 60, s: 100, v: 100 }),
              new Color({ h: 60, s: 100, v: 75 }),
              new Color({ h: 60, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 80 }),
              new Color({ h: 90, s: 33, v: 100 }),
              new Color({ h: 90, s: 66, v: 100 }),
              new Color({ h: 90, s: 100, v: 100 }),
              new Color({ h: 90, s: 100, v: 75 }),
              new Color({ h: 90, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 70 }),
              new Color({ h: 120, s: 33, v: 100 }),
              new Color({ h: 120, s: 66, v: 100 }),
              new Color({ h: 120, s: 100, v: 100 }),
              new Color({ h: 120, s: 100, v: 75 }),
              new Color({ h: 120, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 60 }),
              new Color({ h: 150, s: 33, v: 100 }),
              new Color({ h: 150, s: 66, v: 100 }),
              new Color({ h: 150, s: 100, v: 100 }),
              new Color({ h: 150, s: 100, v: 75 }),
              new Color({ h: 150, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 50 }),
              new Color({ h: 180, s: 33, v: 100 }),
              new Color({ h: 180, s: 66, v: 100 }),
              new Color({ h: 180, s: 100, v: 100 }),
              new Color({ h: 180, s: 100, v: 75 }),
              new Color({ h: 180, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 40 }),
              new Color({ h: 210, s: 33, v: 100 }),
              new Color({ h: 210, s: 66, v: 100 }),
              new Color({ h: 210, s: 100, v: 100 }),
              new Color({ h: 210, s: 100, v: 75 }),
              new Color({ h: 210, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 30 }),
              new Color({ h: 240, s: 33, v: 100 }),
              new Color({ h: 240, s: 66, v: 100 }),
              new Color({ h: 240, s: 100, v: 100 }),
              new Color({ h: 240, s: 100, v: 75 }),
              new Color({ h: 240, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 20 }),
              new Color({ h: 270, s: 33, v: 100 }),
              new Color({ h: 270, s: 66, v: 100 }),
              new Color({ h: 270, s: 100, v: 100 }),
              new Color({ h: 270, s: 100, v: 75 }),
              new Color({ h: 270, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 10 }),
              new Color({ h: 300, s: 33, v: 100 }),
              new Color({ h: 300, s: 66, v: 100 }),
              new Color({ h: 300, s: 100, v: 100 }),
              new Color({ h: 300, s: 100, v: 75 }),
              new Color({ h: 300, s: 100, v: 50 }),
              new Color({ h: 180, s: 0, v: 0 }),
              new Color({ h: 330, s: 33, v: 100 }),
              new Color({ h: 330, s: 66, v: 100 }),
              new Color({ h: 330, s: 100, v: 100 }),
              new Color({ h: 330, s: 100, v: 75 }),
              new Color({ h: 330, s: 100, v: 50 }),
              new Color()
            ]
        },
      images:
        {
            clientPath: '/jPicker/images/', /* Path to image files */
            colorMap:
          {
              width: 256,
              height: 256,
              arrow:
            {
                file: 'mappoint.gif', /* ColorMap arrow icon */
                width: 15,
                height: 15
            }
          },
            colorBar:
          {
              width: 20,
              height: 256,
              arrow:
            {
                file: 'rangearrows.gif', /* ColorBar arrow icon */
                width: 20,
                height: 7
            }
          },
            picker:
          {
              file: 'picker.gif', /* Color Picker icon */
              width: 25,
              height: 24
          }
        },
      localization: /* alter these to change the text presented by the picker (e.g. different language) */
        {
        text:
          {
              title: 'Drag Markers To Pick A Color',
              newColor: 'new',
              currentColor: 'current',
              ok: 'OK',
              cancel: 'Cancel'
          },
        tooltips:
          {
              colors:
            {
                newColor: 'New Color - Press &ldquo;OK&rdquo; To Commit',
                currentColor: 'Click To Revert To Original Color'
            },
              buttons:
            {
                ok: 'Commit To This Color Selection',
                cancel: 'Cancel And Revert To Original Color'
            },
              hue:
            {
                radio: 'Set To &ldquo;Hue&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Hue&rdquo; Value (0-360&deg;)'
            },
              saturation:
            {
                radio: 'Set To &ldquo;Saturation&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Saturation&rdquo; Value (0-100%)'
            },
              value:
            {
                radio: 'Set To &ldquo;Value&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Value&rdquo; Value (0-100%)'
            },
              red:
            {
                radio: 'Set To &ldquo;Red&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Red&rdquo; Value (0-255)'
            },
              green:
            {
                radio: 'Set To &ldquo;Green&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Green&rdquo; Value (0-255)'
            },
              blue:
            {
                radio: 'Set To &ldquo;Blue&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Blue&rdquo; Value (0-255)'
            },
              alpha:
            {
                radio: 'Set To &ldquo;Alpha&rdquo; Color Mode',
                textbox: 'Enter A &ldquo;Alpha&rdquo; Value (0-100)'
            },
              hex:
            {
                textbox: 'Enter A &ldquo;Hex&rdquo; Color Value (#000000-#ffffff)',
                alpha: 'Enter A &ldquo;Alpha&rdquo; Value (#00-#ff)'
            }
          }
    }
  };
})(jQuery, '1.1.6');;
//this file is not used anymore but kept here for further usages which may come
var isIframeApp = false;
if (location.href.indexOf('loginForm') > 0) {
    isIframeApp = true;
}
function addToList(list, items) {
    if (items != null)
        for (var i = 0, n = items.length; i < n; i++)
            list.append('<option value="' + items[i].Id + '" title="' + ((items[i].Description == null) ? '' : items[i].Description) + '">' + items[i].Name + '</option>');

    var options = list.find("option");

    options.sort(function (a, b) {
        if (a.text > b.text) return 1;
        else if (a.text < b.text) return -1;
        else return 0;
    });

    list.empty().append(options);
}

function move(source, dest, all) {
    var selected = source.find("option" + (all ? "" : ":selected"));

    addToList(dest, selected.map(function () {
        var i = $(this);

        return {
            Id: i.val(),
            Name: i.text(),
            Description: i.attr("title")
        };
    }));

    selected.each(function () { $(this).remove(); });
}

function getList(list) {
    var result = [];

    list.find("option").each(function () {
        var i = $(this);

        result.push({
            Id: i.val(),
            Name: i.text(),
            Description: i.attr("title")
        });
    });

    return result;
}

function getListValues(list) {
    var result = [];

    list.find("option").each(function () {
        var i = $(this);

        result.push(i.val());
    });

    return result;
};
(function ($) {
    $.fn.semaphore = function (options) {
        var defaults = {
            images: ["semaphore_blank", "semaphore_gray", "semaphore_yellow", "semaphore_blue", "semaphore_green", "semaphore_red"],
            mappings: [-1, 1, 2, 3, 4],
            imgIdxIntVal: 0
        };

        var parameters = $.extend(defaults, options);

        return this.each(function () {
            var bubbles = new Array();
            var valImgIdxInt;

            //init start
            bubbles = defaults.images;

            var initValImgIdx = $(this).val();

            if (initValImgIdx == "") {
                valImgIdxInt = defaults.imgIdxIntVal;
                $(this).val(defaults.mappings[valImgIdxInt]);
            }
            else {
                valImgIdxInt = defaults.mappings.indexOf(parseInt(initValImgIdx));
            }
            // init stop

            $(this).hide();

            var imgBubbleId = this.id + '_img';
            var imgBubble = '<div class="' + bubbles[valImgIdxInt] + '" id="' + imgBubbleId + '" img_Idx="' + valImgIdxInt + '" inputContainer="' + this.id + '" />';

            if ($(this).attr('test') != this.id + '_img_bubble') {
                $(this).after(imgBubble);
                $(this).attr('test', this.id + '_img_bubble')
            }
            else {
                var valImgIdx = $(this).val();
                valImgIdxInt = defaults.mappings.indexOf(parseInt(initValImgIdx));

                $("#" + this.id + "_img").attr("img_Idx", valImgIdxInt);
                $("#" + this.id + "_img").attr("class", bubbles[valImgIdxInt]);

                $(this).change();

                $("#" + this.id + "_img").off();
            }

            $("#" + this.id + "_img").bind('click', function (ev) {
                if (ev.target.id == this.id) {
                    var valImgIdx = $(ev.target).attr('img_idx');
                    var valImgIdxInt = parseInt(valImgIdx);
                    var inputContainer = '#' + $(ev.target).attr('inputContainer');

                    if (valImgIdxInt < bubbles.length - 1)
                        valImgIdxInt += 1;
                    else
                        valImgIdxInt = 0;

                    $(this).attr("img_Idx", valImgIdxInt);
                    $(this).attr("class", bubbles[valImgIdxInt]);

                    $(inputContainer).val(defaults.mappings[valImgIdxInt]);
                    $(inputContainer).change();
                }
            });
        });
    };
})(jQuery);;
(function($){
 	
	$.fn.TimeLinePlugin = function(options){	
 
		var defaults = {
			
			'monthVal': 0,
			'yearVal': 2013,
			'eventsVal': [],			
			'monthsVal': ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
			'typeVal': 0,
			'clickOnEventFunc': function(val) {alert('Has event on ' + val);},
			'clickOnNoEventFunc': function(val) {alert('Has no event on ' +  val);}
		};
		
		var parameters = $.extend(defaults,options);

		
		return this.each(function(){
			var s;			
			var divId = this.id;			
			var events = new Array();
			var months = [];	
	
			//start init
			m = defaults.monthVal;
			y = defaults.yearVal;
			events = defaults.eventsVal
			months = defaults.monthsVal;	
			type = defaults.typeVal;
			//stop init
					

			if(type == 0)
				s = drawTimelineDays(m, y);			
			else if(type == 1)
					s = drawTimelineMonths(y);
				else if (type == 2)
						s = drawTimelineYears(y);
					else
						s = drawTimeline10Years(y);

			$(this).html(s);
		
		
			$(this).bind('click',function(ev){
				//debugger;
				//if(ev.target == "#eventBtn"){
				//alert('button[id^=#eventBtn]');				
				//alert('ev.target.id=' + ev.target.id);				
				//var v = $('button[id^=#eventBtn]');				
				//alert(ev.target.id);
				divId = this.id;
				
				var date_nr_y = ev.target.attributes['date_event'].value;			
				var date_nr_m = ev.target.attributes['date_event_m'].value;	
				var curTlT = ev.target.attributes['cTlT'].value;
				var year = parseInt(date_nr_y);
				var month = parseInt(date_nr_m);
				var currentType = parseInt(curTlT);
				var day = ev.target.attributes['date_event_d'].value;
				//var s;
				
				if(ev.target.id.indexOf(divId + "_eventBtn") != -1){																							
					if(currentType == -1){
						//alert("event");						
						if(parameters.clickOnEventFunc)	{						
							
							parameters.clickOnEventFunc(day + ' ' + months[month] + ' ' + year);	
						}
					}
					else if(currentType == 0){						
						s = drawTimelineDays(month, year);
						}
					else if(currentType == 1){						
						s = drawTimelineMonths(year);						
						}
					else if(currentType == 2){						
						s = drawTimelineYears(year);						
					}
					else if(currentType == 3){						
						s = drawTimeline10Years(year);						
					}						
				}
				
				if(ev.target.id.indexOf(divId + "_noeventBtn") != -1){
					if(currentType == -1){
						//alert("noevent");
						if(parameters.clickOnNoEventFunc)
							parameters.clickOnNoEventFunc(day + ' ' + months[month] + ' ' + year);
					}
					else if(currentType == 0){						
						s = drawTimelineDays(month, year);
						}
					else if(currentType == 1){						
						s = drawTimelineMonths(year);						
						}
					else if(currentType == 2){						
						s = drawTimelineYears(year);						
					}
					else if(currentType == 3){						
						s = drawTimeline10Years(year);						
					}
				}
				
				if(ev.target.id.indexOf(divId + "_prevBtn") != -1){													
					s = drawTimelinePreviousNext(month, year, -1, currentType);									
				}
				
				if(ev.target.id.indexOf(divId + "_nextBtn") != -1){
					s = drawTimelinePreviousNext(month, year, 1, currentType);									
				}
								
				if(ev.target.id.indexOf(divId + "_header") != -1){
					if(currentType == 1){						
						s = drawTimelineMonths(year);						
					}
					else if(currentType == 2){						
						s = drawTimelineYears(year);						
					}
					else if(currentType == 3){						
						s = drawTimeline10Years(year);						
					}
				}
											
				if(ev.target.id.indexOf(divId + "_img") != -1){				
					if(currentType == -1){						
						if(parameters.clickOnEventFunc)
							parameters.clickOnEventFunc(day + ' ' + months[month] + ' ' + year);
					}
					else if(currentType == 0){						
						s = drawTimelineDays(month, year);
						}
					else if(currentType == 1){						
						s = drawTimelineMonths(year);						
						}
					else if(currentType == 2){						
						s = drawTimelineYears(year);						
					}
					else if(currentType == 3){						
						s = drawTimeline10Years(year);						
					}
				}											
								
				$(this).html(s);
			});
																
								
			function drawTimelineDays(month, year) {
				
				if (!isYearValid(year))
					return;				
				
				var s = '<a class="k-button" id="' + divId + '_header" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + date_str + ' cTlT=' + 1 + '>' +
					months[month] + ' ' + year + '</a><div style="height: 10px;"></div><div class="timeline-scroller"><table border="0" cellspacing="0" cellpadding="0">';

				s += '<tr>';

				var cDate = new Date(year, month, 1);
                     
				var endDate = new Date(cDate.getFullYear(), cDate.getMonth() + 1, 0);         
            
				s += '<td><button class="k-button" id="' + divId  + '_prevBtn" date_event=' + year + ' date_event_m=' + month + ' date_event_d=' + date_str + ' cTlT=' + 0 + ' >&#60</button></td>';            
			
				while (cDate <= endDate) {
					var date_str = cDate.getDate();
					var hasEvent = false;

					for (var i = 0, n = events.length; i < n; i++)
						if (events[i].getTime() == cDate.getTime()) {
							hasEvent = true;
							break;
						}

					s += '<td style="text-align: center" colspan="2" valign="top">' +
						(hasEvent ?
							('<button id="' + divId + '_eventBtn" style="width:46px" class="k-button" date_event=' + cDate.getFullYear() + ' date_event_m=' + month  + ' date_event_d=' + date_str + ' cTlT=-1 >' + date_str + '</button>') :
							('<button id="' + divId + '_noeventBtn" style="width:46px" class="k-button k-state-disabled" date_event=' + cDate.getFullYear() + ' date_event_m=' + month + ' date_event_d=' + date_str +' cTlT=-1 >' + date_str + '</button>')
						) +
						'&#x2500;&#x2500;&#x253c;&#x2500;&#x2500;<br/>' +
						(hasEvent ? ('<img id="'+ divId + '_img " src="Content/Images/event-marker.png" style="border: none;" date_event=' + cDate.getFullYear() + ' date_event_m=' + month + ' date_event_d=' + date_str + ' cTlT=-1 />') : '') +
						'</td>';
						cDate.setDate(cDate.getDate() + 1);
				}
            
				s += '<td><button class="k-button" id="' + divId  + '_nextBtn" date_event=' + year + ' date_event_m=' + month + ' date_event_d=' + date_str + ' cTlT=' + 0 + ' >&#62</button></td>';
 
				s += '</tr></table></div>';           
            
				return s;
			}

			function drawTimelineMonths(year) {			
            
				if (!isYearValid(year))
					return;

				var s = '<a class="k-button"  id="' + divId + '_header" style="display: block;"  date_event=' + year + ' date_event_m=' + 0  + ' date_event_d=' + 1 + ' cTlT=' + 2 + ' >' +
					year + '</a><div style="height: 10px;"></div><div class="timeline-scroller"><table border="0" cellspacing="0" cellpadding="0">';

				s += '<tr>';
            
				s += '<td><button class="k-button" id="' + divId  + '_prevBtn" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 1 + ' >&#60</button></td>';

				for (var m = 0; m < 12; m++) {
					var date_str = months[m];
					var cDate = new Date(year, m, 1);
					var hasEvent = false;

					for (var i = 0, n = events.length; i < n; i++)
						if ((events[i].getYear() == cDate.getYear()) && (events[i].getMonth() == cDate.getMonth())) {
							hasEvent = true;
							break;
						}

					s += '<td style="text-align: center" colspan="2" valign="top">' +
						(hasEvent ?
							('<button id="' + divId  + '_eventBtn" class="k-button" date_event_m =' + (m) + ' date_event = ' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 0 + ' >' + date_str + '</button>') :
							('<button id="' + divId  + '_noeventBtn" class="k-button k-state-disabled" date_event_m =' + (m) + ' date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 0 + '>' + date_str + '</button>')
						) +
						'&#x2500;&#x2500;&#x2500;&#x2500;&#x2500;&#x253c;&#x2500;&#x2500;&#x2500;&#x2500;&#x2500;<br/>' +
						(hasEvent ? ('<img id="'+ divId + '_img " src="Content/Images/event-marker.png" style="border: none;" date_event_m =' + (m) + ' date_event =' + year + ' date_event_d=' + 1 + ' cTlT=' + 0 + ' />') : '') +
						'</td>';
					cDate.setDate(cDate.getDate() + 1);
				}
            
				s += '<td><button class="k-button" id="' + divId  + '_nextBtn" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 1 + '>&#62</button></td>';

				s += '</tr></table></div>';
           
				return s;
			}

			function drawTimelineYears(year) {

				if (!isYearValid(year))
					return;
				
				var startYear = (year / 10).toFixed(0) * 10;
				var endYear = startYear + 9;

				var s = '<a class="k-button"  id="' + divId + '_header" style="display: block;" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 3 + '>' +
					startYear + ' - ' + endYear + '</a><div style="height: 10px;"></div><div class="timeline-scroller"><table border="0" cellspacing="0" cellpadding="0">';

				s += '<tr>';
            
				s += '<td><button class="k-button" id="' + divId  + '_prevBtn" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 2 + '>&#60</button></td>';

				for (var y = startYear; y <= endYear; y++) {
					var date_str = y;
					var cDate = new Date(y, 0, 1);
					var hasEvent = false;

					for (var i = 0, n = events.length; i < n; i++)
						if (events[i].getYear() == cDate.getYear()) {
							hasEvent = true;
							break;
						}

					s += '<td style="text-align: center" colspan="2" valign="top">' +
						(hasEvent ?
							('<button id="' + divId  + '_eventBtn" class="k-button" date_event=' + y + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 1 + ' >' + date_str + '</button>') :
							('<button id="' + divId  + '_noeventBtn" class="k-button k-state-disabled" date_event=' + y + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 1 + ' >' + date_str + '</button>')
						) +
						'&#x2500;&#x2500;&#x2500;&#x253c;&#x2500;&#x2500;&#x2500;<br/>' +
						(hasEvent ? ('<img id="'+ divId + '_img " src="Content/Images/event-marker.png" style="border: none;" date_event=' + y + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 1 + ' />') : '') +
						'</td>';
					cDate.setDate(cDate.getDate() + 1);
				}
            
				s += '<td><button class="k-button" id="' + divId  + '_nextBtn" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 2 + ' >&#62</button></td>';

				s += '</tr></table></div>';
           
				return s;
			}

			function drawTimeline10Years(year) {

				if (!isYearValid(year))
					return;				
	
				var startYear = (year / 100).toFixed(0) * 100;
				var endYear = startYear + 99;
				var s = '<a class="k-button k-state-disabled"  id="' + divId + '_header" style="display: block;" date_event="" date_event_m="" cTlT="">' +
					startYear + ' - ' + endYear + '</a><div style="height: 10px;"></div><div class="timeline-scroller"><table border="0" cellspacing="0" cellpadding="0">';

				s += '<tr>';
            
				s += '<td><button class="k-button" id="' + divId  + '_prevBtn" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 3 + '>&#60</button></td>';

				for (var y = startYear; y <= endYear; y += 10) {
					var date_str = y + "-" + (y + 9);
					var cDate = new Date(y, 1, 1);
					var hasEvent = false;

					for (var i = 0, n = events.length; i < n; i++)
						if ((events[i].getYear() >= cDate.getYear()) && (events[i].getYear() <= cDate.getYear() + 9)) {
							hasEvent = true;
							break;
						}

					s += '<td style="text-align: center" colspan="2" valign="top">' +
						(hasEvent ?
							('<button id="' + divId  + '_eventBtn" class="k-button" date_event=' + y + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 2 + ' >' + date_str + '</button>') :
							('<button id="' + divId  + '_noeventBtn" class="k-button k-state-disabled" date_event=' + y + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 2 + ' >' + date_str + '</button>')
						) +
						'&#x2500;&#x2500;&#x2500;&#x2500;&#x2500;&#x253c;&#x2500;&#x2500;&#x2500;&#x2500;&#x2500;<br/>' +
						(hasEvent ? ('<img id="'+ divId + '_img " src="Content/Images/event-marker.png" style="border: none;" date_event=' + y + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 2 + ' >') : '') +
						'</td>';
					cDate.setDate(cDate.getDate() + 1);
				}
            
				s += '<td><button class="k-button" id="' + divId  + '_nextBtn" date_event=' + year + ' date_event_m=' + 0 + ' date_event_d=' + 1 + ' cTlT=' + 3 + ' >&#62</button></td>';

				s += '</tr></table></div>';
           
				return s;
			}

			//type -> 0 = month, 1 = year, 2 = 10 years, 3 = 100 years;
			//direction -> 0 = previous, 1 = next
			//val -> month or year value        
			function drawTimelinePreviousNext(month, year, direction, type) {			
		
				var startDate = new Date(year, month, 1)

				if (type == 0) {			
					if (direction == -1)
						startDate = new Date(startDate.getFullYear(), startDate.getMonth() - 1, 1);
					else
						startDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1);

					return drawTimelineDays(startDate.getMonth(), startDate.getFullYear());
				}
				else if (type == 1) {
					if (direction == -1)
						year = year - 1;
					else
						year = year + 1;

					return drawTimelineMonths(year);
				}
				else if (type == 2) {
					if (direction == -1)
						year = year - 10;
					else
						year = year + 10;

					return drawTimelineYears(year);
				}
				else {
					if (direction == -1)
						year = year - 100;
					else
						year = year + 100;

					return drawTimeline10Years(year);
				}
			}
		
			function isYearValid(year) {

				if (year < 1900 || year > 2099)
					return false;
				else
					return true;
			}
							
		});		
	};					
		
 })(jQuery);;
/*
    json2.js
    2012-10-08

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html


    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.


    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or '&nbsp;'),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the value

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'


            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'


        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    This is a reference implementation. You are free to copy, modify, or
    redistribute.
*/

/*jslint evil: true, regexp: true */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (typeof JSON !== 'object') {
    JSON = {};
}

(function () {
    'use strict';

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear()     + '-' +
                    f(this.getUTCMonth() + 1) + '-' +
                    f(this.getUTCDate())      + 'T' +
                    f(this.getUTCHours())     + ':' +
                    f(this.getUTCMinutes())   + ':' +
                    f(this.getUTCSeconds())   + 'Z'
                : null;
        };

        String.prototype.toJSON      =
            Number.prototype.toJSON  =
            Boolean.prototype.toJSON = function (key) {
                return this.valueOf();
            };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string'
                ? c
                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0
                    ? '[]'
                    : gap
                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
                    : '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === 'string') {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0
                ? '{}'
                : gap
                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
                : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                    typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/
                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function'
                    ? walk({'': j}, '')
                    : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());
;
var showDownloadStartMessage = false;
var showDownloadEndMessage = false;

//not used anymore
function createUUID() {
    // http://www.ietf.org/rfc/rfc4122.txt
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr(s[19] & 0x3 | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "";

    var uuid = s.join("");
    return uuid;
}


function nothing() {
}


//get outer html
$.fn.outerHTML = function () {
    // IE, Chrome & Safari will comply with the non-standard outerHTML, all others (FF) will have a fall-back for cloning
    return !this.length ? this : this[0].outerHTML || (
      function (el) {
          var div = document.createElement('div');
          div.appendChild(el.cloneNode(true));
          var contents = div.innerHTML;
          div = null;
          return contents;
      })(this[0]);
};

//get messages from db
function getMessages(componentId, allIds, nonAlert) {
    var ids = "";
    if (allIds) {
        if (allIds.length == 0) {
            return;
        }

        for (var i = 0; i < allIds.length; i++) {
            ids = ids + allIds[i].Id + ";";
        }
    }
    else {
        ids = null;
    }
    log("getMessages(" + componentId + ", " + ids + ")");
    if (componentId)
        ajaxCall((isIframeApp? "/":"") + 'Desktop/GetMessages/' + componentId, null, getMessagesCallback, componentId, allIds);
    else
        ajaxCall((isIframeApp? "/":"") + 'Desktop/GetMessages/', null, getMessagesCallback, componentId, allIds);
}

////logout
//function logout() {
//    $('#logouta')[0].click()
//}

//var messagesAlreadySended = [];
//receive messsages and if interval 0 show them in the bottom part or alert if interval > 0
function getMessagesCallback(data, compId, allIds) {
    var winId = compId;
    if (allIds && allIds.length > 0) {
        winId = allIds[0].Id;
    }

    var messagesArray = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i].IntervalDB > 0) {
            messagesArray.push({ id: data[i].Id, text: data[i].MessageText });
        }
    }

    if (messagesArray.length > 0)
        showInstantMessages(messagesArray, winId);

    if (allIds) {
        for (var j = 0; j < allIds.length; j++) {
            winId = allIds[j].Id;
            var text = "";
            let i = 0;
            for ( i = 0; i < data.length; i++) {
                if (data[i].IntervalDB == 0) {
                    if (data[i].MessageText == "LOGOUT_USER") {
                        setTimeout("logout()", parseInt(timeOutUntilLogout) * 60 * 1000);
                        confirmPrompt(logoutMessageText, function () { });
                        ajaxCall((isIframeApp ? "/" : "") + 'Desktop/ConfirmMessage/' + data[i].Id + "?onlyLastSendDate=false", null, confirmMessageCallback);
                    }
                    else
                        if (data[i].MessageText == "RELOAD_START_MENU") {
                            getStartMenu();
                            ajaxCall((isIframeApp ? "/" : "") + 'Desktop/ConfirmMessage/' + data[i].Id + "?onlyLastSendDate=false", null, confirmMessageCallback);
                        }
                        else {
                            if (text.length > 0) {
                                text += '</br>' + data[i].MessageText;
                            }
                            else {
                                text += data[i].MessageText;
                            }
                        }
                }
            }

            appendMesagesDiv(winId, text);
        }
    }
}

//alert from messages
function showInstantMessages(messagesArray, componentId) {
    var yes = function () {
        ajaxCall((isIframeApp ? "/" : "") + 'Desktop/ConfirmMessage/' + messagesArray[0].id + "?onlyLastSendDate=false", null, confirmMessageCallback);
        messagesArray.splice(0, 1);
        if (messagesArray.length > 0) {
            showInstantMessages(messagesArray);
        }
    };

    var noEmpty = function () {
        messagesArray.splice(0, 1);
        if (messagesArray.length > 0) {
            showInstantMessages(messagesArray);
        }
    };

    var no = function () {
        ajaxCall((isIframeApp ? "/" : "") + 'Desktop/ConfirmMessage/' + messagesArray[0].id + "?onlyLastSendDate=true", null, confirmMessageCallback);
        messagesArray.splice(0, 1);
        if (messagesArray.length > 0) {
            showInstantMessages(messagesArray);
        }
    };
    if (!desktopInitilizing) {
        ajaxCall((isIframeApp ? "/" : "") + 'Desktop/ConfirmMessage/' + messagesArray[0].id + "?onlyLastSendDate=true", null, confirmMessageCallback);
        confirmPrompt(messagesArray[0].text, yes, noEmpty);
    }
    else
        if (componentId == null) {
            confirmPrompt(messagesArray[0].text, yes, no);
        }
}

function confirmMessageCallback(data) {
    log("Message confirmed successfully");
}

var initialExportButtonTitle = '';
function changeExportButton(btnClass, setCancel) {
    $('.' + btnClass).removeClass('cancelExportGrid');
    $('.' + btnClass).attr('title', initialExportButtonTitle);
    if (setCancel) {
        $('.' + btnClass).attr('title', cancelDownloadText);
        $('.' + btnClass).addClass('cancelExportGrid');
    }
}

//export data (for now only in sms)
function exportData(urlSession, url, gridName, btnExportClass) {
    var obj = null;
    if (getFilterObjForSession)
        obj = getFilterObjForSession(gridName);
    if (showDownloadStartMessage) {
        confirmPrompt(downloadStartedtext, function () { });
    }

    //send information on server and store in SESSION
    ajaxCall(urlSession, JSON.stringify(obj), exportDataCallback, url, gridName, btnExportClass);
}

function exportDataCallback(data, url, gridName, btnExportClass) {
    var obj = null;

    var download = function () {
        if (btnExportClass) {
            initialExportButtonTitle = $('.' + btnExportClass).attr('title');
            changeExportButton(btnExportClass, true);
        }
        $.fileDownload(url,
                {
                    successCallback: function () {
                        if (showDownloadEndMessage) {
                            confirmPrompt(downloadFinishtext, function () { });
                        }
                        if (btnExportClass) {
                            changeExportButton(btnExportClass, false);
                        }
                    },
                    failCallback: function () {
                        if (downloadCancelByUser) {
                            downloadCancelByUser = null;
                            confirmPrompt(downloadStoppedtext, function () { });
                        }
                        else {
                            confirmPrompt(downloadFailedtext, function () { });
                        }

                        if (btnExportClass) {
                            changeExportButton(btnExportClass, false);
                        }
                    },
                    httpMethod: "GET",
                    data: obj
                }
                );
    };

    //if (url.indexOf("PDFExportFormatter") > 0 && obj.verifyMaxColumns) {
    //    var columns = obj.columnNames.split("~");
    //    if (columns.length > maxColumnsInExport)
    //        confirmPrompt(exportMultipleColumns, download, null);
    //    else
    //        download();
    //}
    //else
    download();
}

function exportDataReport(url, getObj) {
    var obj = null;
    if (getObj)
        obj = getObj();
    var download = function () {
        $.fileDownload(url,
                {
                    successCallback: function () {
                        confirmPrompt(downloadFinishtext, function () { });
                    },
                    failCallback: function () {
                        confirmPrompt(downloadFailedtext, function () { });
                    },
                    httpMethod: "GET",
                    data: obj
                }
                );
    };
    download();

}

function exportDataReportCallback(data) {
    log("data exported with report succesfully");
}

function DateFmt(fstr) {
    this.formatString = fstr;

    var mthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    var dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    var zeroPad = function (number) {
        return ("0" + number).substr(-2, 2);
    };

    var dateMarkers = {
        d: ['getDate', function(v) { return zeroPad(v); }],
        m: ['getMonth', function(v) { return zeroPad(v + 1); }],
        n: ['getMonth', function (v) { return mthNames[v]; }],
        w: ['getDay', function (v) { return dayNames[v]; }],
        y: ['getFullYear'],
        H: ['getHours', function(v) { return zeroPad(v); }],
        M: ['getMinutes', function(v) { return zeroPad(v); }],
        S: ['getSeconds', function(v) { return zeroPad(v); }],
        i: ['toISOString']
    };

    this.format = function (date) {
        var dateTxt = this.formatString.replace(/%(.)/g, function (m, p) {
            var rv = date[dateMarkers[p][0]]();

            if (dateMarkers[p][1] != null){
                rv = dateMarkers[p][1](rv);
            }
            return rv;

        });
        return dateTxt;
    };
}

function dateTimePicker(control) {
    $(control).kendoDateTimePicker({
        format: "dd/MM/yyyy HH:mm:ss",
        timeFormat: "HH:mm:ss"
    });
}

function timePicker(control) {
    $(control).kendoTimePicker({
        format: "HH:mm:ss",
        type: "time"
    });
}


//do not delete the following function
function emptyFilter() {
    return { filterId: "" };
}

// formatiert aktuelles Datum + Zeit für Rapid-Interface 
function getFormattedDate(date) {
    date = date || new Date();

    let year = date.getFullYear();
    let month = formatDateNumber(date.getMonth() + 1);
    let day = formatDateNumber(date.getDate());

    let hours = formatDateNumber(date.getHours() + 1);
    let min = formatDateNumber(date.getMinutes());
    let sec = formatDateNumber(date.getSeconds());

    return year + '-' + month + '-' + day + ' ' + hours + ':' + min + ':' + sec;
}

function formatDateNumber(number) {
    if (!number && number !== 0) {
        return '';
    }

    let str = number;
    if (typeof number === 'number') {
        str = number.toString();
    }

    while (str.length < 2) {
        str = '0' + str;
    }

    return str;
}

/**
 * @param {number} val Number to be rounded.
 * @param {number} fracDig Number of fractional digits after rounding.
 * @return {number} The rounded number, with fracDig fractional digits
 */
function round(val, fracDig) {
    fracDig = fracDig || 0;
    if (fracDig === 0) {
        return Math.round(val);
    }

    let pow = Math.pow(10, fracDig);

    return Math.round(val * pow) / pow;
}

// Stringify, das 'circular references' beachtet
function saveStringify(o) {
    let ret = '';
    if (o) {
        let cache = [];
        ret = JSON.stringify(o, function(key, value) {
            if (typeof value === 'object' && value !== null) {
                if (cache.indexOf(value) !== -1) {
                    // Circular reference found, discard key;
                    return;
                }
                // Store value
                cache.push(value);
            }
            return value;
        });
        cache = null;
    }
    return ret;
}

// TODO bessere art den fehler mitzuteilen
function checkForSoapFault(node) {
    if (typeof node == 'string') {
        node = parseXml(node);
    }

    if (node) {
        let fcarr = node.getElementsByTagName('faultcode');
        let fsarr = node.getElementsByTagName('faultstring');

        if (fcarr.length > 0 && fsarr.length > 0) {
            let fc, fs;
            if (fcarr[0]) {
                fc = fcarr[0].nodeValue || fcarr[0].textContent;
            }

            if (fsarr[0]) {
                fs = fsarr[0].nodeValue || fsarr[0].textContent;
            }

            if (fs || fc) {
                let err = (fc + ' - ' || '') + (fs || 'Fehler im Soap-Request');
                console.log(err);
                displayErrorInStatusInfo(err, "Vwc.Panel.Datatable");
                return true;
            }
        }
    }

    return false;
}

function degToRad(angle) {
    return angle / 180 * Math.PI;
}

function radToDeg(rad) {
    return rad * 180 / Math.PI;
}

function getAvailableFonts() {
    /**
     * JavaScript code to detect available availability of a
     * particular font in a browser using JavaScript and CSS.
     *
     * Author : Lalit Patel
     * Website: http://www.lalit.org/lab/javascript-css-font-detect/
     * License: Apache Software License 2.0
     *          http://www.apache.org/licenses/LICENSE-2.0
     * Version: 0.15 (21 Sep 2009)
     *          Changed comparision font to default from sans-default-default,
     *          as in FF3.0 font of child element didn't fallback
     *          to parent element if the font is missing.
     * Version: 0.2 (04 Mar 2012)
     *          Comparing font against all the 3 generic font families ie,
     *          'monospace', 'sans-serif' and 'sans'. If it doesn't match all 3
     *          then that font is 100% not available in the system
     * Version: 0.3 (24 Mar 2012)
     *          Replaced sans with serif in the list of baseFonts
     */
    let Detector = function() {
        // a font will be compared against all the three default fonts.
        // and if it doesn't match all 3 then that font is not available.
        let baseFonts = ['monospace', 'sans-serif', 'serif'];

        //we use m or w because these two characters take up the maximum width.
        // And we use a LLi so that the same matching fonts can get separated
        let testString = "mmmmmmmmmmlli";

        //we test using 72px font size, we may use any size. I guess larger the better.
        let testSize = '72px';

        let h = document.getElementsByTagName("body")[0];

        // create a SPAN in the document to get the width of the text we use to test
        let s = document.createElement("span");
        s.style.fontSize = testSize;
        s.innerHTML = testString;
        let defaultWidth = {};
        let defaultHeight = {};
        for (let index in baseFonts) {
            //get the default width for the three base fonts
            s.style.fontFamily = baseFonts[index];
            h.appendChild(s);
            defaultWidth[baseFonts[index]] = s.offsetWidth; //width for the default font
            defaultHeight[baseFonts[index]] = s.offsetHeight; //height for the defualt font
            h.removeChild(s);
        }

        function detect(font) {
            let detected = false;
            for (let index in baseFonts) {
                s.style.fontFamily = font + ',' + baseFonts[index]; // name of the font along with the base font for fallback.
                h.appendChild(s);
                let matched = s.offsetWidth != defaultWidth[baseFonts[index]] || s.offsetHeight != defaultHeight[baseFonts[index]];
                h.removeChild(s);
                detected = detected || matched;
            }
            return detected;
        }

        this.detect = detect;
    };

    let ret = [];
    // from https://www.w3schools.com/cssref/css_websafe_fonts.asp
    let fontFamilies = [
        // serif fonts
        'Georgia',
        'Palatino Linotype',
        'Book Antiqua',
        'Palatino',
        'Times New Roman',
        'Times',
        // sans-serif fonts
        'Arial',
        'Helvetica',
        'Arial Black',
        'Gadget',
        'Comic Sans MS',
        'Impact',
        'Charcoal',
        'Lucida Sans Unicode',
        'Lucida Grande',
        'Tahoma',
        'Geneva',
        'Trebuchet MS',
        'Verdana',
        // monospace fonts
        'Courier New',
        'Courier',
        'Lucida Console',
        'Monaco'
    ];
    let detector = new Detector();
    for (let i = 0; i < fontFamilies.length; ++i) {
        let ff = fontFamilies[i];
        let detected = detector.detect(ff);
        if (detected) {
            ret.push(ff);
        }
    }
    detector = null;
    return ret;
}

function parseXml(obj) {
    return new DOMParser().parseFromString(obj, 'application/xml');
}

function parseKilometerToStationResponse(xml, hasBlockNr) {
    return parseKilometrierungResponse(xml, hasBlockNr ? 'station' : 'stationen'); 
}

function parseKilometrierungResponse(xml, tagName) {
    let ret = {};
    if (xml) {
        if (typeof xml === 'string') {
            xml = parseXml(xml);
        }
        if (checkForSoapFault(xml)) {
            // fehler im soap-request
            return null;
        }
                   
        let elements = xml.getElementsByTagName(tagName);
        if (elements && elements.length > 0) {
            let stationElement = elements[0];
            if (stationElement && stationElement.hasChildNodes()) {
                let children = stationElement.childNodes;
                for (let i = 0; i < children.length; ++i) {
                    let child = children[i];
                    let ln = child.localName;
                    let val = child.nodeValue || child.textContent;
                    switch (ln) {
                        case 'VST':
                        case 'BST': {
                            if (typeof val === 'string') {
                                val = Number.parseInt(val);
                            }
                            ret.station = val;
                            break;
                        }
                        case 'LEN': {
                            ret.len = val;
                            break;
                        }
                        case 'vonKartenblatt': {
                            ret.vonKartenblatt = val;
                            break;
                        }
                        case 'vonNkLfd': {
                            ret.vonNkLfd = val;
                            break;
                        }
                        case 'vonZusatz': {
                            ret.vonZusatz = val === 'O' ? '' : val;
                            break;
                        }
                        case 'nachKartenblatt': {
                            ret.nachKartenblatt = val;
                            break;
                        }
                        case 'nachNkLfd': {
                            ret.nachNkLfd = val;
                            break;
                        }
                        case 'nachZusatz': {
                            ret.nachZusatz = val === 'O' ? '' : val;
                            break;
                        }
                        case 'inStatRi': {
                            ret.inRichtung = val == 'true';
                            break;
                        }
                        case 'kilometer': {
                            if (typeof val === 'string') {
                                val = parseFloat(val);
                            }
                            ret.kilometer = val;
                        }
                    }
                }
            }
        }
    }
    ret.vnk = getNk(ret.vonKartenblatt, ret.vonNkLfd, ret.vonZusatz);
    ret.nnk = getNk(ret.nachKartenblatt, ret.nachNkLfd, ret.nachZusatz);

    return ret;
}

function parseStationToKilometerResponse(xml) {
    let ret = {};
    if (xml) {
        if (typeof xml === 'string') {
            xml = parseXml(xml);
        }
        if (checkForSoapFault(xml)) {
            // fehler im soap-request
            return null;
        }
                   
        let elements = xml.getElementsByTagName('kilometer');
        if (elements && elements.length > 0) {
            let kilometerElement = elements[0];
            ret = kilometerElement.nodeValue || kilometerElement.textContent;
        }
    }

    return ret;
}

function getNk(kartenblatt, lfd, zusatz) {
    kartenblatt = typeof kartenblatt === 'number' ? kartenblatt.toString() : kartenblatt;
    lfd = typeof lfd === 'number' ? lfd.toString() : lfd;
    zusatz = typeof zusatz === 'number' ? zusatz.toString() : zusatz;

    let nk = kartenblatt;

    while (lfd.length < 3) {
        lfd = '0' + lfd;
    }
    nk += lfd;

    if (zusatz || zusatz == '0') {
        nk += zusatz;
    }

    return nk;
}

function getPartsFromNk(nk) {
    let ret = {};

    ret.kartenblatt = nk.substring(0, 4);
    if (ret.kartenblatt) {
        ret.kartenblatt = Number.parseInt(ret.kartenblatt);
    }
    ret.lfd = nk.substring(4, 7);
    if (ret.lfd) {
        ret.lfd = Number.parseInt(ret.lfd);
    }
    ret.zusatz = nk.substring(7, 8);

    return ret;
}

function enterWaitState() {
    Vwc.temp.cursor = $('html, body').css('cursor');
    $('html, body').css('cursor', 'wait');
}

function leaveWaitState() {
    $('html, body').css('cursor', Vwc.temp.cursor || 'default');
};
