    /**

     * Bullet charts

     */

    $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {

        type: 'bullet',



        init: function (el, values, options, width, height) {

            var min, max, vals;

            bullet._super.init.call(this, el, values, options, width, height);



            // values: target, performance, range1, range2, range3

            this.values = values = normalizeValues(values);

            // target or performance could be null

            vals = values.slice();

            vals[0] = vals[0] === null ? vals[2] : vals[0];

            vals[1] = values[1] === null ? vals[2] : vals[1];

            min = Math.min.apply(Math, values);

            max = Math.max.apply(Math, values);

            if (options.get('base') === undefined) {

                min = min < 0 ? min : 0;

            } else {

                min = options.get('base');

            }

            this.min = min;

            this.max = max;

            this.range = max - min;

            this.shapes = {};

            this.valueShapes = {};

            this.regiondata = {};

            this.width = width = options.get('width') === 'auto' ? '4.0em' : width;

            this.target = this.$el.simpledraw(width, height, options.get('composite'));

            if (!values.length) {

                this.disabled = true;

            }

            this.initTarget();

        },



        getRegion: function (el, x, y) {

            var shapeid = this.target.getShapeAt(el, x, y);

            return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;

        },



        getCurrentRegionFields: function () {

            var currentRegion = this.currentRegion;

            return {

                fieldkey: currentRegion.substr(0, 1),

                value: this.values[currentRegion.substr(1)],

                region: currentRegion

            };

        },



        changeHighlight: function (highlight) {

            var currentRegion = this.currentRegion,

                shapeid = this.valueShapes[currentRegion],

                shape;

            delete this.shapes[shapeid];

            switch (currentRegion.substr(0, 1)) {

                case 'r':

                    shape = this.renderRange(currentRegion.substr(1), highlight);

                    break;

                case 'p':

                    shape = this.renderPerformance(highlight);

                    break;

                case 't':

                    shape = this.renderTarget(highlight);

                    break;

            }

            this.valueShapes[currentRegion] = shape.id;

            this.shapes[shape.id] = currentRegion;

            this.target.replaceWithShape(shapeid, shape);

        },



        renderRange: function (rn, highlight) {

            var rangeval = this.values[rn],

                rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),

                color = this.options.get('rangeColors')[rn - 2];

            if (highlight) {

                color = this.calcHighlightColor(color, this.options);

            }

            return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);

        },



        renderPerformance: function (highlight) {

            var perfval = this.values[1],

                perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),

                color = this.options.get('performanceColor');

            if (highlight) {

                color = this.calcHighlightColor(color, this.options);

            }

            return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,

                Math.round(this.canvasHeight * 0.4) - 1, color, color);

        },



        renderTarget: function (highlight) {

            var targetval = this.values[0],

                x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),

                targettop = Math.round(this.canvasHeight * 0.10),

                targetheight = this.canvasHeight - (targettop * 2),

                color = this.options.get('targetColor');

            if (highlight) {

                color = this.calcHighlightColor(color, this.options);

            }

            return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);

        },



        render: function () {

            var vlen = this.values.length,

                target = this.target,

                i, shape;

            if (!bullet._super.render.call(this)) {

                return;

            }

            for (i = 2; i < vlen; i++) {

                shape = this.renderRange(i).append();

                this.shapes[shape.id] = 'r' + i;

                this.valueShapes['r' + i] = shape.id;

            }

            if (this.values[1] !== null) {

                shape = this.renderPerformance().append();

                this.shapes[shape.id] = 'p1';

                this.valueShapes.p1 = shape.id;

            }

            if (this.values[0] !== null) {

                shape = this.renderTarget().append();

                this.shapes[shape.id] = 't0';

                this.valueShapes.t0 = shape.id;

            }

            target.render();

        }

    });



