<commit_before>var Path = require('path');
var FontLib = require('font-lib');

var FontEditor = (function () {
    var _super = WorkSpace;

    // ================================================================================
    // const
    // ================================================================================

    var _atlasBoundColor = new paper.Color(85/255, 85/255, 179/255, 0.9);

    var _sampleText =
'The quick brown fox jumps over the lazy dog\n' +
'abcdefghijklmnopqrstuvwxyz\n' +
'ABCDEFGHIJKLMNOPQRSTUVWXYZ\n' +
'1234567890;:_,.-("*!?\')';

    var _styleFields = ['fontFamily', 'fontSize', 'fontWeight',
                        'fillColor', 'strokeColor', 'strokeWidth', 'strokeJoin', 'miterLimit',
                        'shadowColor', 'shadowBlur', 'shadowOffset',
                        'dashOffset', 'dashArray'];

    // ================================================================================
    // constructor
    // ================================================================================

    function FontEditor(canvas) {
        this.atlas = new FIRE.Atlas();
        this.atlas.allowRotate = false;

        _super.call(this, canvas);

        _initLayers(this);

        this._sampleText = _sampleText; // 目前不提供单独的预览功能，sampleText里面包含的所有字符最终都会被输出。
        this._displayBounds = false;
        this._font = null;              // font obj created by font-lib
        this._charTable = {};
        this._sortedCharList = null;    // sorted keys of _charTable
        this.fontTable = {names: [], paths: []};
        _updateCharTable(this);

        // font --------------------------------

        this._fontFamily = '';
        this._fontSize = 50;
        // for fonts that provide only normal and bold, 100-500 are normal, and 600-900 are bold.
        this._fontWeight = 'normal'; // normal(Same as 400) | bold(Same as 700) | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 // bolder lighter

        // color --------------------------------

        this._fillColor = 'black';

        // stroke --------------------------------

        this._strokeColor = 'white';
        this._strokeWidth = 2;
        /**
         * The shape to be used at the segments and corners of Path items when they have a stroke.
         * String('miter', 'round', 'bevel')
         */
        this._strokeJoin = 'round';
        /**
         * When two line segments meet at a sharp angle and miter joins have been specified for item.strokeJoin,
         * it is possible for the miter to extend far beyond the item.strokeWidth of the path. The miterLimit
         * imposes a limit on the ratio of the miter length to the item.strokeWidth.
         */
        this._miterLimit = 10;

        // shadow --------------------------------

        this._shadowColor = [0, 0, 0, 0.5];
        this._shadowBlur = 2;
        this._shadowOffset = new paper.Point(5, 8);

        // dash --------------------------------

        /**
         * The dash offset of the stroke.
         */
        this._dashOffset = 0;
        /**
         * Specifies an array containing the dash and gap lengths of the stroke.
         */
        this._dashArray = null;

        var self = this;
        console.time('enum fonts');
        FontLib.getFontTable(function(data) {
            console.timeEnd('enum fonts');
            _setFontTable(self, data);
        }, navigator.language);
    }
    FIRE.extend(FontEditor, _super);

    // ================================================================================
    // properties
    // ================================================================================

    var defineGetter = function (constructor, fieldList) {
        fieldList.forEach(function (field) {
            var _field = '_' + field;
            constructor.prototype.__defineGetter__(field, function () {
                return this[_field];
            });
        });
    };

    defineGetter (FontEditor, _styleFields);
    defineGetter (FontEditor, ['sampleText', 'displayBounds']);

    // define setter for style fields
    _styleFields.forEach(function (field) {
        var _field = '_' + field;
        FontEditor.prototype.__defineSetter__(field, function (val) {
            this[_field] = val;
            this._recreateAtlas(false);
        });
    });

    FontEditor.prototype.__defineSetter__('sampleText', function (str) {
        this._sampleText = sampleText;
        _updateCharTable();
    });

    FontEditor.prototype.__defineSetter__('displayBounds', function (value) {
        this._displayBounds = value;
        this.repaint();
    });

    // ================================================================================
    // public
    // ================================================================================

    FontEditor.prototype.exportBmFontTxt = function (file) {
        this._font.setSize(this._fontSize);

        // build sorted char list
        this._sortedCharList = Object.keys(this._charTable);
        this._sortedCharList.sort();

        // build data
        var data = {};
        _buildBmFontInfo(this, data, file);
        _buildBmGlyphData(this, data);
        _buildBmKerningData(this, data);

        // to string
        var text = convertIntoText(data);

        return text;
    };

    // ================================================================================
    // overridable
    // ================================================================================

    FontEditor.prototype.repaint = function () {
        _super.prototype.repaint.call(this);
        this._recreateAtlas(false);
    };

    FontEditor.prototype._doUpdateCanvas = function () {
        _super.prototype._doUpdateCanvas.call(this);
        _updateCanvas(this);
    };

    FontEditor.prototype._recreateBackground = function () {
        _super.prototype._recreateBackground.call(this);
        this._border.fillColor = 'white';
    };

    FontEditor.prototype._recreateAtlas = function (forExport) {
        var self = this;
        console.log('_recreateAtlas font family: ' + self.fontFamily);

        // create atlas
        console.time('create atlas');

        var style = {};
        _styleFields.forEach(function (field) {
            style[field] = self['_' + field];
        });
        var text = new paper.PointText(paper.Item.NO_INSERT);
        text.getStrokeBounds = _getRenderBounds(text.getStrokeBounds, style);   // reserve shadow's size when rasterizing

        self.atlas.clear();
        for (var char in self._charTable) {
            text.style = style;
            text.content = char;

            // check valid
            var bounds = text.bounds;
            if (bounds.area === 0) {
                continue;   // wont skip space, but return
            }

            // create image
            var img = document.createElement('img');
            var raster = text.rasterize();
            var canvas = raster.canvas;
            img.src = canvas.toDataURL('image/png');
            //console.log('char: ' + char + ' w: ' + img.width + ' h: ' + img.height/* + ' s: ' + img.src*/);

            // create texture
            var tex = new FIRE.SpriteTexture(img);
            tex.name = char;
            self._charTable[char] = tex;

            // get trim rect to caculate actual size including shadow
            var trimRect = FIRE.getTrimRect(canvas, self.atlas.trimThreshold);
            tex.trimX = trimRect.x;
            tex.trimY = trimRect.y;
            tex.width = trimRect.width;
            tex.height = trimRect.height;

            // if visible, pack it into atlas
            if (tex.width > 0 && tex.height > 0) {
                self.atlas.add(tex);
            }
        }
        console.timeEnd('create atlas');

        // packing
        console.time('packing');
        self.atlas.sort();
        self.atlas.layout();
        console.timeEnd('packing');

        // create raster
        var addBounds = !forExport && self._displayBounds;
        if (!forExport) {
            self._charLayer.activate();
            self._charLayer.removeChildren();
        }
        WorkSpace.createAtlasRasters(self.atlas, addBounds);

        // update
        if (!forExport) {
            _updateCanvas(self);
        }
        paper.view.update();
    };

    // ================================================================================
    // private
    // ================================================================================

    var _initLayers = function (self) {
        self._charLayer = WorkSpace.createLayer();        // to draw chars

        self._cameraLayer.addChildren([
            // BOTTOM (sorted by create order) -----------
            self._charLayer,
            // TOP ---------------------------------------
        ]);
    };

    var _updateCharTable = function (self) {
        self._charTable = {};
        self._sortedCharList = null;

        var charTable = self._charTable;
        var text = self._sampleText;
        var atlas = self.atlas;
        for (var i = 0, len = text.length; i < len; ++i) {
            var char = text[i];
            var spriteTex = charTable[char];
            if (!spriteTex) {
                var tex = null;
                charTable[char] = tex;
            }
        }
        if (self.fontFaimly) {
            self._paperProject.activate();
            self._recreateAtlas(flase);
        }
    };

    var _getRenderBounds = function (strokeBoundsGetter, style) {
        var leftExpand = style.shadowBlur - style.shadowOffset.x;
        var rightExpand = style.shadowBlur + style.shadowOffset.x;
        var topExpand = style.shadowBlur - style.shadowOffset.y;
        var bottomExpand = style.shadowBlur + style.shadowOffset.y;

        var expandWidth = Math.max(leftExpand, 0) + Math.max(rightExpand, 0);
        var expandHeight = Math.max(topExpand, 0) + Math.max(bottomExpand, 0);

        return function () {
            var bounds = strokeBoundsGetter.call(this);
            return bounds.expand(expandWidth, expandHeight);
        };
    };

    var _updateCanvas = function (self) {
        var posFilter = Math.round;
        var children = self._charLayer.children;
        for (var i = 0; i < children.length; ++i) {
            var child = children[i];
            var isRaster = child.data && child.data.texture;
            if (!isRaster) {
                continue;
            }
            // update char atlas
            var tex = child.data.texture;
            child.position = [posFilter(tex.x * self._zoom), posFilter(tex.y * self._zoom)];
            child.scaling = [self._zoom, self._zoom];
            // update debug rect
            if (self._displayBounds) {
                var left = posFilter(tex.x * self._zoom);
                var top = posFilter(tex.y * self._zoom);
                var w = posFilter(tex.rotatedWidth * self._zoom);
                var h = posFilter(tex.rotatedHeight * self._zoom);
                var bounds = child.data.boundsItem;
                bounds.size = [w, h];
                bounds.position = new paper.Rectangle(left, top, w, h).center;
                bounds.fillColor = _atlasBoundColor;
            }
        }
    };

    var _setFontTable = function (self, data) {
        console.log(data);
        self.fontTable = data;
        var fontIndex = 16;
        if (data.names.length > fontIndex) {
            self.fontFamily = data.names[fontIndex];
            self._font = FontLib.loadFont(data.paths[fontIndex]);
        }
        self._paperProject.activate();
        //self._recreateAtlas(false);
    };

    var _buildBmFontInfo = function (self, data, file) {
        // set info
        data.face = self._fontFamily;
        data.size = self._fontSize;
        var boldStyles = ['bold', '600', '700', '800', '900', 'bolder'];
        var bold = boldStyles.indexOf(self._fontWeight) !== -1;
        data.bold = (bold ? 1 : 0);
        data.italic = 0;    // TODO 保存skew
        data.charset = "";  // not used
        data.unicode = 1;   // not used
        data.stretchH = 100;// not used
        data.smooth = 1;    // not used
        data.aa = 1;        // not used
        data.padding = [0, 0, 0, 0];        // not used
        var spacing = self.atlas.customPadding;
        data.spacing = [spacing, spacing];
        data.outline = 1;   // not used

        // set common
        data.lineHeight = self._font.size.height;
        data.base = self._font.size.ascender;
        data.scaleW = self.atlas.width;
        data.scaleH = self.atlas.height;
        data.pages = 1;     // not used
        data.packed = 0;    // not used

        // set page
        data.id = 0;        // not used
        data.file = file;

        // chars count
        data.count = self._sortedCharList.length;

        return data;
    };

    var _buildBmGlyphData = function (self, data) {
        var output = [];
        data.charList = output;

        var id = 0, x = 0, y = 0, width = 0, height = 0, xoffset = 0, yoffset = 0, xadvance = 0,/* page = 0, chnl = 0,*/ letter = '';
        // cached variables
        var charList = self._sortedCharList;
        var charTable = self._charTable;
        var round = Math.round;
        var font = self._font;

        for (var i = 0, len = charList.length; i < len; i++) {
            letter = charList[i];
            var tex = charTable[letter];
            if (!tex) {
                continue;
            }
            id = letter.charCodeAt(0);
            x = tex.x;
            y = tex.y;
            width = tex.width;
            height = tex.height;
            xoffset = tex.trimX;
            yoffset = tex.trimY;
            xadvance = font.getAdvanceX(letter);
            if (xadvance !== null) {
                if (letter === ' ') {
                    letter = 'space';
                }
                output.push([id, x, y, width, height, xoffset, yoffset, round(xadvance),/* page, chnl,*/ letter]);
            }
            else {
                console.warn('failed to load char code: ' + id);
            }
        }
    };

    var _buildBmKerningData = function (self, data) {
        var hasKerning = (self._font.face_flags & FontLib.FT.FACE_FLAG_KERNING) > 0;
        if (hasKerning === false) {
            return;
        }
        var output = [];
        data.kerningList = output;

        // predefined variables
        var first = 0, second = 0, amount = 0, firstCharIndex = 0, secondCharIndex = 0, error = 0;
        var kerningVec = {x: 0, y: 0};
        // cached variables
        var charList = self._sortedCharList;
        var font = self._font;
        var kerningMode = FontLib.FT.KERNING_DEFAULT;
        var getCharIndex = FontLib.FT.Get_Char_Index;
        var getKerning = FontLib.FT.Get_Kerning;

        for (var i = 0, len = charList.length; i < len; i++) {
            first = charList[i].charCodeAt(0);
            firstCharIndex = getCharIndex(font, first);
            if (firstCharIndex === 0) {
                continue;
            }
            for (var j = 0; j < len; j++) {
                second = charList[j].charCodeAt(0);
                secondCharIndex = getCharIndex(font, second);
                if (secondCharIndex === 0) {
                    continue;
                }
                error = getKerning(font, firstCharIndex, secondCharIndex, kerningMode, kerningVec);
                if (!error && kerningVec.x !== 0) {
                    output.push([first, second, kerningVec.x / 64]);
                }
            }
        }
    };

    FontEditor.__testOnly__ = {
        _buildBmFontInfo: _buildBmFontInfo,
        _buildBmGlyphData: _buildBmGlyphData,
        _buildBmKerningData: _buildBmKerningData,
    };

    return FontEditor;
})();
<commit_msg>fix incorrect offset value<commit_after>var Path = require('path');
var FontLib = require('font-lib');

var FontEditor = (function () {
    var _super = WorkSpace;

    // ================================================================================
    // const
    // ================================================================================

    var _atlasBoundColor = new paper.Color(85/255, 85/255, 179/255, 0.9);

    var _sampleText =
'The quick brown fox jumps over the lazy dog\n' +
'abcdefghijklmnopqrstuvwxyz\n' +
'ABCDEFGHIJKLMNOPQRSTUVWXYZ\n' +
'1234567890;:_,.-("*!?\')';

    var _styleFields = ['fontFamily', 'fontSize', 'fontWeight',
                        'fillColor', 'strokeColor', 'strokeWidth', 'strokeJoin', 'miterLimit',
                        'shadowColor', 'shadowBlur', 'shadowOffset',
                        'dashOffset', 'dashArray'];

    // ================================================================================
    // constructor
    // ================================================================================

    function FontEditor(canvas) {
        this.atlas = new FIRE.Atlas();
        this.atlas.allowRotate = false;

        _super.call(this, canvas);

        _initLayers(this);

        this._sampleText = _sampleText; // 目前不提供单独的预览功能，sampleText里面包含的所有字符最终都会被输出。
        this._displayBounds = false;
        this._font = null;              // font obj created by font-lib
        this._charTable = {};
        this._sortedCharList = null;    // sorted keys of _charTable
        this.fontTable = {names: [], paths: []};
        _updateCharTable(this);

        // font --------------------------------

        this._fontFamily = '';
        this._fontSize = 50;
        // for fonts that provide only normal and bold, 100-500 are normal, and 600-900 are bold.
        this._fontWeight = 'normal'; // normal(Same as 400) | bold(Same as 700) | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 // bolder lighter

        // color --------------------------------

        this._fillColor = 'black';

        // stroke --------------------------------

        this._strokeColor = 'white';
        this._strokeWidth = 2;
        /**
         * The shape to be used at the segments and corners of Path items when they have a stroke.
         * String('miter', 'round', 'bevel')
         */
        this._strokeJoin = 'round';
        /**
         * When two line segments meet at a sharp angle and miter joins have been specified for item.strokeJoin,
         * it is possible for the miter to extend far beyond the item.strokeWidth of the path. The miterLimit
         * imposes a limit on the ratio of the miter length to the item.strokeWidth.
         */
        this._miterLimit = 10;

        // shadow --------------------------------

        this._shadowColor = [0, 0, 0, 0.5];
        this._shadowBlur = 2;
        this._shadowOffset = new paper.Point(5, 8);

        // dash --------------------------------

        /**
         * The dash offset of the stroke.
         */
        this._dashOffset = 0;
        /**
         * Specifies an array containing the dash and gap lengths of the stroke.
         */
        this._dashArray = null;

        var self = this;
        console.time('enum fonts');
        FontLib.getFontTable(function(data) {
            console.timeEnd('enum fonts');
            _setFontTable(self, data);
        }, navigator.language);
    }
    FIRE.extend(FontEditor, _super);

    // ================================================================================
    // properties
    // ================================================================================

    var defineGetter = function (constructor, fieldList) {
        fieldList.forEach(function (field) {
            var _field = '_' + field;
            constructor.prototype.__defineGetter__(field, function () {
                return this[_field];
            });
        });
    };

    defineGetter (FontEditor, _styleFields);
    defineGetter (FontEditor, ['sampleText', 'displayBounds']);

    // define setter for style fields
    _styleFields.forEach(function (field) {
        var _field = '_' + field;
        FontEditor.prototype.__defineSetter__(field, function (val) {
            this[_field] = val;
            this._recreateAtlas(false);
        });
    });

    FontEditor.prototype.__defineSetter__('sampleText', function (str) {
        this._sampleText = sampleText;
        _updateCharTable();
    });

    FontEditor.prototype.__defineSetter__('displayBounds', function (value) {
        this._displayBounds = value;
        this.repaint();
    });

    // ================================================================================
    // public
    // ================================================================================

    FontEditor.prototype.exportBmFontTxt = function (file) {
        this._font.setSize(this._fontSize);

        // build sorted char list
        this._sortedCharList = Object.keys(this._charTable);
        this._sortedCharList.sort();

        // build data
        var data = {};
        _buildBmFontInfo(this, data, file);
        _buildBmGlyphData(this, data);
        _buildBmKerningData(this, data);

        // to string
        var text = convertIntoText(data);

        return text;
    };

    // ================================================================================
    // overridable
    // ================================================================================

    FontEditor.prototype.repaint = function () {
        _super.prototype.repaint.call(this);
        this._recreateAtlas(false);
    };

    FontEditor.prototype._doUpdateCanvas = function () {
        _super.prototype._doUpdateCanvas.call(this);
        _updateCanvas(this);
    };

    FontEditor.prototype._recreateBackground = function () {
        _super.prototype._recreateBackground.call(this);
        this._border.fillColor = 'white';
    };

    FontEditor.prototype._recreateAtlas = function (forExport) {
        var self = this;
        console.log('_recreateAtlas font family: ' + self.fontFamily);

        // create atlas
        console.time('create atlas');

        var style = {};
        _styleFields.forEach(function (field) {
            style[field] = self['_' + field];
        });
        var text = new paper.PointText(paper.Item.NO_INSERT);
        text.getStrokeBounds = _getRenderBounds(text.getStrokeBounds, style);   // reserve shadow's size when rasterizing

        self.atlas.clear();
        for (var char in self._charTable) {
            text.style = style;
            text.content = char;

            // check valid
            var bounds = text.bounds;
            if (bounds.area === 0) {
                continue;   // wont skip space, but return
            }

            // create image
            var img = document.createElement('img');
            var raster = text.rasterize();
            var canvas = raster.canvas;
            img.src = canvas.toDataURL('image/png');
            //console.log('char: ' + char + ' w: ' + img.width + ' h: ' + img.height/* + ' s: ' + img.src*/);

            // create texture
            var tex = new FIRE.SpriteTexture(img);
            tex.name = char;
            self._charTable[char] = tex;

            // get trim rect to caculate actual size including shadow
            var trimRect = FIRE.getTrimRect(canvas, self.atlas.trimThreshold);
            tex.trimX = trimRect.x;
            tex.trimY = trimRect.y;
            tex.width = trimRect.width;
            tex.height = trimRect.height;

            // if visible, pack it into atlas
            if (tex.width > 0 && tex.height > 0) {
                self.atlas.add(tex);
            }
        }
        console.timeEnd('create atlas');

        // packing
        console.time('packing');
        self.atlas.sort();
        self.atlas.layout();
        console.timeEnd('packing');

        // create raster
        var addBounds = !forExport && self._displayBounds;
        if (!forExport) {
            self._charLayer.activate();
            self._charLayer.removeChildren();
        }
        WorkSpace.createAtlasRasters(self.atlas, addBounds);

        // update
        if (!forExport) {
            _updateCanvas(self);
        }
        paper.view.update();
    };

    // ================================================================================
    // private
    // ================================================================================

    var _initLayers = function (self) {
        self._charLayer = WorkSpace.createLayer();        // to draw chars

        self._cameraLayer.addChildren([
            // BOTTOM (sorted by create order) -----------
            self._charLayer,
            // TOP ---------------------------------------
        ]);
    };

    var _updateCharTable = function (self) {
        self._charTable = {};
        self._sortedCharList = null;

        var charTable = self._charTable;
        var text = self._sampleText;
        var atlas = self.atlas;
        for (var i = 0, len = text.length; i < len; ++i) {
            var char = text[i];
            var spriteTex = charTable[char];
            if (!spriteTex) {
                var tex = null;
                charTable[char] = tex;
            }
        }
        if (self.fontFaimly) {
            self._paperProject.activate();
            self._recreateAtlas(flase);
        }
    };

    var _getRenderBounds = function (strokeBoundsGetter, style) {
        var leftExpand = Math.max(style.shadowBlur - style.shadowOffset.x, 0);
        var rightExpand = Math.max(style.shadowBlur + style.shadowOffset.x, 0);
        var topExpand = Math.max(style.shadowBlur - style.shadowOffset.y, 0);
        var bottomExpand = Math.max(style.shadowBlur + style.shadowOffset.y, 0);

        return function () {
            var bounds = strokeBoundsGetter.call(this);
            bounds.left -= leftExpand;
            bounds.right += rightExpand;
            bounds.top -= topExpand;
            bounds.bottom += bottomExpand;
            return bounds;
        };
    };

    var _updateCanvas = function (self) {
        var posFilter = Math.round;
        var children = self._charLayer.children;
        for (var i = 0; i < children.length; ++i) {
            var child = children[i];
            var isRaster = child.data && child.data.texture;
            if (!isRaster) {
                continue;
            }
            // update char atlas
            var tex = child.data.texture;
            child.position = [posFilter(tex.x * self._zoom), posFilter(tex.y * self._zoom)];
            child.scaling = [self._zoom, self._zoom];
            // update debug rect
            if (self._displayBounds) {
                var left = posFilter(tex.x * self._zoom);
                var top = posFilter(tex.y * self._zoom);
                var w = posFilter(tex.rotatedWidth * self._zoom);
                var h = posFilter(tex.rotatedHeight * self._zoom);
                var bounds = child.data.boundsItem;
                bounds.size = [w, h];
                bounds.position = new paper.Rectangle(left, top, w, h).center;
                bounds.fillColor = _atlasBoundColor;
            }
        }
    };

    var _setFontTable = function (self, data) {
        console.log(data);
        self.fontTable = data;
        var fontIndex = 16;
        if (data.names.length > fontIndex) {
            self.fontFamily = data.names[fontIndex];
            self._font = FontLib.loadFont(data.paths[fontIndex]);
        }
        self._paperProject.activate();
        //self._recreateAtlas(false);
    };

    var _buildBmFontInfo = function (self, data, file) {
        // set info
        data.face = self._fontFamily;
        data.size = self._fontSize;
        var boldStyles = ['bold', '600', '700', '800', '900', 'bolder'];
        var bold = boldStyles.indexOf(self._fontWeight) !== -1;
        data.bold = (bold ? 1 : 0);
        data.italic = 0;    // TODO 保存skew
        data.charset = "";  // not used
        data.unicode = 1;   // not used
        data.stretchH = 100;// not used
        data.smooth = 1;    // not used
        data.aa = 1;        // not used
        data.padding = [0, 0, 0, 0];        // not used
        var spacing = self.atlas.customPadding;
        data.spacing = [spacing, spacing];
        data.outline = 1;   // not used

        // set common
        data.lineHeight = self._font.size.height;
        data.base = self._font.size.ascender;
        data.scaleW = self.atlas.width;
        data.scaleH = self.atlas.height;
        data.pages = 1;     // not used
        data.packed = 0;    // not used

        // set page
        data.id = 0;        // not used
        data.file = file;

        // chars count
        data.count = self._sortedCharList.length;

        return data;
    };

    var _buildBmGlyphData = function (self, data) {
        var output = [];
        data.charList = output;

        var id = 0, x = 0, y = 0, width = 0, height = 0, xoffset = 0, yoffset = 0, xadvance = 0,/* page = 0, chnl = 0,*/ letter = '';
        // cached variables
        var charList = self._sortedCharList;
        var charTable = self._charTable;
        var round = Math.round;
        var font = self._font;

        for (var i = 0, len = charList.length; i < len; i++) {
            letter = charList[i];
            var tex = charTable[letter];
            if (!tex) {
                continue;
            }
            id = letter.charCodeAt(0);
            x = tex.x;
            y = tex.y;
            width = tex.width;
            height = tex.height;
            xoffset = tex.trimX;
            yoffset = tex.trimY;
            xadvance = font.getAdvanceX(letter);
            if (xadvance !== null) {
                if (letter === ' ') {
                    letter = 'space';
                }
                output.push([id, x, y, width, height, xoffset, yoffset, round(xadvance),/* page, chnl,*/ letter]);
            }
            else {
                console.warn('failed to load char code: ' + id);
            }
        }
    };

    var _buildBmKerningData = function (self, data) {
        var hasKerning = (self._font.face_flags & FontLib.FT.FACE_FLAG_KERNING) > 0;
        if (hasKerning === false) {
            return;
        }
        var output = [];
        data.kerningList = output;

        // predefined variables
        var first = 0, second = 0, amount = 0, firstCharIndex = 0, secondCharIndex = 0, error = 0;
        var kerningVec = {x: 0, y: 0};
        // cached variables
        var charList = self._sortedCharList;
        var font = self._font;
        var kerningMode = FontLib.FT.KERNING_DEFAULT;
        var getCharIndex = FontLib.FT.Get_Char_Index;
        var getKerning = FontLib.FT.Get_Kerning;

        for (var i = 0, len = charList.length; i < len; i++) {
            first = charList[i].charCodeAt(0);
            firstCharIndex = getCharIndex(font, first);
            if (firstCharIndex === 0) {
                continue;
            }
            for (var j = 0; j < len; j++) {
                second = charList[j].charCodeAt(0);
                secondCharIndex = getCharIndex(font, second);
                if (secondCharIndex === 0) {
                    continue;
                }
                error = getKerning(font, firstCharIndex, secondCharIndex, kerningMode, kerningVec);
                if (!error && kerningVec.x !== 0) {
                    output.push([first, second, kerningVec.x / 64]);
                }
            }
        }
    };

    FontEditor.__testOnly__ = {
        _buildBmFontInfo: _buildBmFontInfo,
        _buildBmGlyphData: _buildBmGlyphData,
        _buildBmKerningData: _buildBmKerningData,
    };

    return FontEditor;
})();
<|endoftext|>


<commit_before>(function() {

window.Api = function(attributes) {
    var defaults;

    attributes || (attributes = {});
    if ((defaults = this.defaults))
        attributes = _.extend({}, defaults, attributes);

    this.attributes = {};
    this.set(attributes);
};

_.extend(window.Api.prototype, {
    defaults: {
        authAsBase64 : '', // provides username+password Base64 encoded
        authRequired : false,
        server : 'localhost', // url of the server
        port : 8081, // port on which the server listens
        ssl : false,
        error : {"errorid": "EBADCALL",
                "message": "Request couldn't be sent",
                "details": "Your Request contains syntactical mistakes"
               }
    },

    set: function(attrs) {
        if (!attrs)
            return this;

        for (var attr in attrs)
            this.attributes[attr] = attrs[attr];

        return this;
    },

    get: function(attr) {
        return this.attributes[attr];
    },

    /* send
     * sends given request to server. with or without authentfication.
     * handles callback from reqData
     * param: reqData
     *          .type chooses how the request should be send. POST or GET.
     *          .suffix chooses algorithm, info or modi.
     *          .request String that contains the request.
     *          .callback function should be called when done.
     */

    send : function (reqData) {
        var url = "", event = {};
        if(_.isUndefined(reqData) || _.isNull(reqData)) return false;
        if(_.isUndefined(reqData.callback) || _.isNull(reqData.callback)) return false;
        if(_.isUndefined(reqData.suffix) || !reqData.suffix) return false;
        if(_.isNull(reqData.process) || _.isUndefined(reqData.process)) reqData.process = true;
        reqData.type || (reqData.type = 'GET');
        reqData.request || (reqData.request = {});

        if (!_.isNull(this.get('server')) && !_.isUndefined(this.get('server'))) {
            url +=  this.get('ssl') ? 'https://' : 'http://' +
                    this.get('server') + ':' +
                    (!_.isNaN(this.get('port')) ? this.get('port') : 80);
        }
        url += '/' + reqData.suffix;

        // init event for events and bind callback to it
        _.extend(event, Backbone.Events);
        if (_.isFunction(reqData.callback))
            event.bind('request', reqData.callback);

        // method performs an asyncronous HTTP request with or without
        // authentication.
        // performs a callback, successful or not
        var that = this;
        $.ajax({
            url: url,
            cache: false,
            type: reqData.type,
            accepts: 'json',
            dataType: 'json',
            contentType: 'application/json; charset="utf-8"',
            crossDomain: true,
            data: reqData.type == 'POST' ? JSON.stringify(reqData.request) : reqData.request,
            processData: reqData.process,
            beforeSend: function (jqXHR, settings) {
                if (that.get('authRequired')) {
                    settings.headers = { Authorization: that.get('authAsBase64') };
                }
            },
            success: function (data, textStatus, jqXHR) {
            	var obj = jqXHR.responseText;
                if (_.isString(obj))
                    obj = JSON.parse(obj);
                event.trigger('request', obj, true);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var text = jqXHR.responseText;
                if (!_.isUndefined(jqXHR.responseText) || jqXHR.responseText === "")
                    text = errorThrown;

            	var obj = text;
                if (_.isString(obj))
                    obj = JSON.parse(obj);
                event.trigger('request', obj, false);
            }
        });

        return true;
    },

    /* serverInformation
     * aks' server for information about the server
     */
    serverInformation : function (args) {
        var that = this;
        return this.send({
            suffix : 'info',
            request : {},
            callback: function (text, success) {
            	if(text.servertype == "private")
//                if (!_.isNaN(text.sslport) && !_.isUndefined(text.sslport))
                    that.set({'ssl': true, 'port': text.sslport, 'authRequired': true});
                if (_.isFunction(args.callback))
                        args.callback(text, success);
            }
        });
    },

    /* registerUser
     * creates new user account
     * param: userObject containing info about user
     */
    registerUser: function (args) {
        if(!args || !args.userObject)
            return false;
        this.send({
            type : 'POST',
            suffix : 'registeruser',
            request : args.userObject,
            callback: _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* authUser
     * confirmes user.
     * param: email email-adress of user
     * param: password that belongs to email
     */
    authUser : function (args) {
        if (!args || !args.email || !args.password)
            return false;

        this.set({'authAsBase64': Base64.encode(args.email + ':' + args.password)});

        this.send({
            suffix: 'authuser',
            callback: _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* getUser
     * get user data by id or own data.
     * param: id of requested user, null for own data
     */
    getUser : function (args) {
        if (!args.id || _.isNaN(args.id)) {
            this.send({
                suffix : 'getuser',
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        } else {
            this.send({
                suffix : 'getuser?ID=' + args.id,
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        }

        return true;
    },

    /* updateUser
     * change user data by id or own
     * param: id of user you want to change, null if to change own
     */
    updateUser : function (args) {
        if(!args || !args.userObject)
            return false;
        if (!args.id || _.isNaN(args.id)) {
            this.send({
                type : 'POST',
                suffix : 'updateuser',
                request : args.userObject,
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        } else {
            this.send({
                type : 'POST',
                suffix : 'updateuser?ID=' + args.id,
                request : args.userObject,
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        }

        return true;
    },

    /* listRequests
     * lists all requests that have been made
     * param: id of single user, null if general request
     * param: limit max number of items
     * param: offset of first item
     */
    listRequests : function (args) {
        if(!args || !args.limit || !args.offset || args.offset<0)
            return false;
        if (isNaN(args.id)) {
            this.send({
                type : 'POST',
                suffix : 'listrequests?Limit=' + args.limit + '&Offset=' + args.offset,
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        } else {
            this.send({
                type : 'POST',
                suffix : 'listrequests?ID=' + args.id +
                         '&Limit=' + args.limit + '&Offset=' + args.offset,
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        }

        return true;
    },

    /* listUsers
     * lists user from server
     * param: limit max numbers of users
     * param: offset of first user
     */
    listUsers : function (args) {
        if(!args || !args.limit || !args.offset || args.offset<0)
            return false;
        this.send({
            suffix : 'listusers?Limit=' + args.limit + '&Offset=' + args.offset,
            request : '',
            callback : _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* deleteUser
     * deletes user from server
     * param: id of user that should be deleted
     */
    deleteUser : function (args) {
        if(!args || !args.id || isNaN(args.id))
            return false;
        this.send({
            suffix : 'deleteuser?ID=' + args.id,
            request : '',
            callback : _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* alg
     * sends algorithm calculation request
     * use params request or one for each request element
     * param: alg shortname of desired alg
     * param: request contains problem instance (format as alg specification)
     * param: points, version, constraints as alg spec
     */
    alg : function (args) {
		var thisrequest;
        if(!args || !args.alg)
            return false;

		// use given request or make own
		if(args.request)
			thisrequest = args.request;
		else{
			if(!args.points) return false;
			thisrequest = {
		        version: args.version || 1,
		        points: args.points,
		        constraints: args.constraints || {}
            }
		}
        this.send({
            type : 'POST',
            suffix : 'alg' + args.alg,
            request : thisrequest,
            process: false,
            callback : _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    }
});

}).call(this);
<commit_msg>Fix url generation when using ssl<commit_after>(function() {

window.Api = function(attributes) {
    var defaults;

    attributes || (attributes = {});
    if ((defaults = this.defaults))
        attributes = _.extend({}, defaults, attributes);

    this.attributes = {};
    this.set(attributes);
};

_.extend(window.Api.prototype, {
    defaults: {
        authAsBase64 : '', // provides username+password Base64 encoded
        authRequired : false,
        server : 'localhost', // url of the server
        port : 8081, // port on which the server listens
        ssl : false,
        error : {"errorid": "EBADCALL",
                "message": "Request couldn't be sent",
                "details": "Your Request contains syntactical mistakes"
               }
    },

    set: function(attrs) {
        if (!attrs)
            return this;

        for (var attr in attrs)
            this.attributes[attr] = attrs[attr];

        return this;
    },

    get: function(attr) {
        return this.attributes[attr];
    },

    /* send
     * sends given request to server. with or without authentfication.
     * handles callback from reqData
     * param: reqData
     *          .type chooses how the request should be send. POST or GET.
     *          .suffix chooses algorithm, info or modi.
     *          .request String that contains the request.
     *          .callback function should be called when done.
     */

    send : function (reqData) {
        var url = "", event = {};
        if(_.isUndefined(reqData) || _.isNull(reqData)) return false;
        if(_.isUndefined(reqData.callback) || _.isNull(reqData.callback)) return false;
        if(_.isUndefined(reqData.suffix) || !reqData.suffix) return false;
        if(_.isNull(reqData.process) || _.isUndefined(reqData.process)) reqData.process = true;
        reqData.type || (reqData.type = 'GET');
        reqData.request || (reqData.request = {});

        if (!_.isNull(this.get('server')) && !_.isUndefined(this.get('server'))) {
            url +=  (this.get('ssl') ? 'https://' : 'http://') +
                    this.get('server') + ':' +
                    (!_.isNaN(this.get('port')) ? this.get('port') : 80);
        }
        url += '/' + reqData.suffix;

        // init event for events and bind callback to it
        _.extend(event, Backbone.Events);
        if (_.isFunction(reqData.callback))
            event.bind('request', reqData.callback);

        // method performs an asyncronous HTTP request with or without
        // authentication.
        // performs a callback, successful or not
        var that = this;
        $.ajax({
            url: url,
            cache: false,
            type: reqData.type,
            accepts: 'json',
            dataType: 'json',
            contentType: 'application/json; charset="utf-8"',
            crossDomain: true,
            data: reqData.type == 'POST' ? JSON.stringify(reqData.request) : reqData.request,
            processData: reqData.process,
            beforeSend: function (jqXHR, settings) {
                if (that.get('authRequired')) {
                    settings.headers = { Authorization: that.get('authAsBase64') };
                }
            },
            success: function (data, textStatus, jqXHR) {
            	var obj = jqXHR.responseText;
                if (_.isString(obj))
                    obj = JSON.parse(obj);
                event.trigger('request', obj, true);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var text = jqXHR.responseText;
                if (!_.isUndefined(jqXHR.responseText) || jqXHR.responseText === "")
                    text = errorThrown;

            	var obj = text;
                if (_.isString(obj))
                    obj = JSON.parse(obj);
                event.trigger('request', obj, false);
            }
        });

        return true;
    },

    /* serverInformation
     * aks' server for information about the server
     */
    serverInformation : function (args) {
        var that = this;
        return this.send({
            suffix : 'info',
            request : {},
            callback: function (text, success) {
            	if(text.servertype == "private")
//                if (!_.isNaN(text.sslport) && !_.isUndefined(text.sslport))
                    that.set({'ssl': true, 'port': text.sslport, 'authRequired': true});
                if (_.isFunction(args.callback))
                        args.callback(text, success);
            }
        });
    },

    /* registerUser
     * creates new user account
     * param: userObject containing info about user
     */
    registerUser: function (args) {
        if(!args || !args.userObject)
            return false;
        this.send({
            type : 'POST',
            suffix : 'registeruser',
            request : args.userObject,
            callback: _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* authUser
     * confirmes user.
     * param: email email-adress of user
     * param: password that belongs to email
     */
    authUser : function (args) {
        if (!args || !args.email || !args.password)
            return false;

        this.set({'authAsBase64': Base64.encode(args.email + ':' + args.password)});

        this.send({
            suffix: 'authuser',
            callback: _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* getUser
     * get user data by id or own data.
     * param: id of requested user, null for own data
     */
    getUser : function (args) {
        if (!args.id || _.isNaN(args.id)) {
            this.send({
                suffix : 'getuser',
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        } else {
            this.send({
                suffix : 'getuser?ID=' + args.id,
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        }

        return true;
    },

    /* updateUser
     * change user data by id or own
     * param: id of user you want to change, null if to change own
     */
    updateUser : function (args) {
        if(!args || !args.userObject)
            return false;
        if (!args.id || _.isNaN(args.id)) {
            this.send({
                type : 'POST',
                suffix : 'updateuser',
                request : args.userObject,
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        } else {
            this.send({
                type : 'POST',
                suffix : 'updateuser?ID=' + args.id,
                request : args.userObject,
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        }

        return true;
    },

    /* listRequests
     * lists all requests that have been made
     * param: id of single user, null if general request
     * param: limit max number of items
     * param: offset of first item
     */
    listRequests : function (args) {
        if(!args || !args.limit || !args.offset || args.offset<0)
            return false;
        if (isNaN(args.id)) {
            this.send({
                type : 'POST',
                suffix : 'listrequests?Limit=' + args.limit + '&Offset=' + args.offset,
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        } else {
            this.send({
                type : 'POST',
                suffix : 'listrequests?ID=' + args.id +
                         '&Limit=' + args.limit + '&Offset=' + args.offset,
                request : '',
                callback : _.isFunction(args.callback) ? args.callback : null
            });
        }

        return true;
    },

    /* listUsers
     * lists user from server
     * param: limit max numbers of users
     * param: offset of first user
     */
    listUsers : function (args) {
        if(!args || !args.limit || !args.offset || args.offset<0)
            return false;
        this.send({
            suffix : 'listusers?Limit=' + args.limit + '&Offset=' + args.offset,
            request : '',
            callback : _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* deleteUser
     * deletes user from server
     * param: id of user that should be deleted
     */
    deleteUser : function (args) {
        if(!args || !args.id || isNaN(args.id))
            return false;
        this.send({
            suffix : 'deleteuser?ID=' + args.id,
            request : '',
            callback : _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    },

    /* alg
     * sends algorithm calculation request
     * use params request or one for each request element
     * param: alg shortname of desired alg
     * param: request contains problem instance (format as alg specification)
     * param: points, version, constraints as alg spec
     */
    alg : function (args) {
		var thisrequest;
        if(!args || !args.alg)
            return false;

		// use given request or make own
		if(args.request)
			thisrequest = args.request;
		else{
			if(!args.points) return false;
			thisrequest = {
		        version: args.version || 1,
		        points: args.points,
		        constraints: args.constraints || {}
            }
		}
        this.send({
            type : 'POST',
            suffix : 'alg' + args.alg,
            request : thisrequest,
            process: false,
            callback : _.isFunction(args.callback) ? args.callback : null
        });

        return true;
    }
});

}).call(this);
<|endoftext|>


<commit_before>;(function(){//IFEE

angular.module('brewKeeper')
  .controller('createNewRecipe', function($scope, $http, $location){
    $scope.recipe = { }//Might need to prepopulate this with empty strings for each key... Maybe...
    $scope.submit=function(){
      $http.post('https://brew-keeper-api.herokuapp.com/api/users/don.pablo/recipes/', $scope.recipe)
        // .then(function() {
        // })
        .success(function (data) {
          $location.path('/users/don.pablo/recipes/1');
        })
    // $scope.recipe= { };
  }
  $('.addSteps').on('click', function() {
    $('.addSteps').removeClass('hidden');
  });//Reveal "Add Step" when new recipe form is submitted.
  })//controller for creating new recipe
  .controller('createNewStep', function($scope, $http){
    $scope.step = { }//Might need to prepopulate this with empty strings for each key... Maybe...
    $scope.submit=function(){
      $http.post('urlendpoint', $scope.step);//ADD ACTUAL ENDPOINT HERE!
      $scope.step= { };
    }
  })//controller for creating new step

})();//END IFEE

/* Eventually, it would be good to have the submitted form's information show up in place of the blank form so that the add new steps will be filled out instead of a new recipe form.  Then, as each step is added, it's info will show alongside the recipe info. */
<commit_msg>Wire submit of new recipe to redirect to that recipe's page.<commit_after>;(function(){//IFEE

angular.module('brewKeeper')
  .controller('createNewRecipe', function($scope, $http, $location){
    $scope.recipe = { }//Might need to prepopulate this with empty strings for each key... Maybe...
    $scope.submit=function(){
      $http.post('https://brew-keeper-api.herokuapp.com/api/users/don.pablo/recipes/', $scope.recipe)
        // .then(function() {
        // })
        // $resource.get()
        .success(function (data) {
          var id = data.id
          $location.path('/users/don.pablo/recipes/' + id);
        })
    $scope.recipe= { };
  }
  $('.addSteps').on('click', function() {
    $('.addSteps').removeClass('hidden');
  });//Reveal "Add Step" when new recipe form is submitted.
  })//controller for creating new recipe
  .controller('createNewStep', function($scope, $http){
    $scope.step = { }//Might need to prepopulate this with empty strings for each key... Maybe...
    $scope.submit=function(){
      $http.post('urlendpoint', $scope.step);//ADD ACTUAL ENDPOINT HERE!
      $scope.step= { };
    }
  })//controller for creating new step

})();//END IFEE

/* Eventually, it would be good to have the submitted form's information show up in place of the blank form so that the add new steps will be filled out instead of a new recipe form.  Then, as each step is added, it's info will show alongside the recipe info. */
<|endoftext|>


<commit_before>
var Gui = window.require('nw.gui')

module.exports = Tray = function()
{
  this._hires = this.hires()

  var icon    = ( this._hires ) ? 'anchor-black-@2x.png' : 'anchor-black.png'
    , alticon = ( this._hires ) ? 'anchor-white-@2x.png' : 'anchor-white.png'

  // Create a tray icon
  this._tray = new Gui.Tray({
      title:   ''
    , icon:    'assets/img/' + icon
    , alticon: 'assets/img/' + alticon
  })

  return this
}

//  test for retina / high resolution / high pixel density.
Tray.prototype.hires = function()
{
  // starts with default value for modern browsers
  var dpr = window.devicePixelRatio ||

  // fallback for IE
      (window.screen.deviceXDPI / window.screen.logicalXDPI) ||

  // default value
      1;

  return !!(dpr > 1);
}

// Get _tray instance
Tray.prototype.get = function()
{
  return this._tray
}

// Set new icon
Tray.prototype.set = function( icon )
{
  if( this._hires )
    icon = icon + '-@2x'

  this._tray.icon = icon + '.png'
}
<commit_msg>tray manager class<commit_after>/**
 * Squid Desktop
 *
 * Display menubar icon and
 * manage main window visibility
 *
 */

'use strict';

var Gui = window.require('nw.gui')

var Tray = function( hires )
{
  this._HIRES = hires

  // Setup menubar icon
  // depending on screen resolution and OS theme
  var icon    = ( this._HIRES ) ? 'anchor-black-@2x.png' : 'anchor-black.png'
    , alticon = ( this._HIRES ) ? 'anchor-white-@2x.png' : 'anchor-white.png'

  // Create a tray icon
  this._TRAY = new Gui.Tray({
      title:   ''
    , icon:    'assets/img/' + icon
    , alticon: 'assets/img/' + alticon
  })

  // Minimal Menu bar item
  var nativeMenuBar = new Gui.Menu({ type: 'menubar' })

  nativeMenuBar.createMacBuiltin('Squid')

  Gui.Window.get().menu = nativeMenuBar

  // Test, to remove
  this._TRAY.on( 'click', function()
  {
    window.require('nw.gui').Window.open('new.html', {
        'position': 'center'
      , 'focus':    true
      , 'toolbar':  true
      , 'frame':    true
      , 'width':    475
      , 'height':   330
    })
  })
}

// Get _TRAY instance
Tray.prototype.get = function()
{
  return this._TRAY
}

// Update menubar icon icon
Tray.prototype.set = function( icon )
{
  if( this._HIRES )
    icon = icon + '-@2x'

  this._TRAY.icon = icon + '.png'
}

module.exports = Tray
<|endoftext|>


<commit_before>/**
 * @author Oscar Fonts <oscar.fonts@geomati.co>
 */
define(['SOS', 'leaflet', 'proj4', 'proj4leaflet', 'leaflet-label'], function(SOS, L, proj4) {

    proj4.defs("EPSG:23031", "+title= ED50 / UTM zone 31N +proj=utm +zone=31 +ellps=intl +units=m +no_defs +towgs84=-181.5,-90.3,-187.2,0.144,0.492,-0.394,17.57");

    var inputs = ["service", "offering", "features", "maxInitialZoom"];

    return {
        inputs: inputs,
        init: function(config, renderTo) {
            var map = L.map(renderTo, {
                dragging: false,
                touchZoom: false,
                scrollWheelZoom: false,
                doubleClickZoom: false,
                boxZoom: false,
                zoomControl: false
            }).setView([30, 0], 2);

            L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {
                subdomains: '1234',
                minZoom: 2,
                maxZoom: 14,
                attribution: 'OpenStreetMap | MapQuest'
            }).addTo(map);

            SOS.setUrl(config.service);
            read();

            function read() {
                SOS.getCapabilities(function(offerings) {
                    var addFoIs = function(features) {
                        var geojson = L.Proj.geoJson(fois2geojson(features), {
                            onEachFeature: function(feature, layer) {
                                if (feature.properties && feature.properties.name) {
                                    layer.bindLabel(feature.properties.name).addTo(map);
                                }
                            }
                        });
                        geojson.addTo(map);
                        map.fitBounds(geojson.getBounds(), {
                            maxZoom: config.maxInitialZoom ? parseInt(config.maxInitialZoom) : 14
                        });
                    };
                    for (var i in offerings) {
                        var offering = offerings[i];
                        if (offering.identifier == config.offering) {
                            SOS.getFeatureOfInterest(offering.procedure[0], addFoIs);
                        }
                    }
                });
            }

            function isArray(obj) {
                return Object.prototype.toString.call(obj) === '[object Array]';
            }

            function isInArray(value, array) {
                return array.indexOf(value) > -1;
            }

            function fois2geojson(fois) {
                var config_features = isArray(config.features) ? config.features : JSON.parse(config.features);
                var features = [];
                for (var i in fois) {
                    var foi = fois[i];
                    if (foi.geometry && (!config_features.length || isInArray(foi.identifier.value, config.features))) {
                        var feature = {
                            type: "Feature",
                            geometry: foi.geometry,
                            id: foi.identifier.value,
                            properties: {
                                name: foi.name.value
                            }
                        };
                        // Transform CRS from link type to name type.
                        // See spec: http://geojson.org/geojson-spec.html#named-crs
                        // See impl: https://github.com/kartena/Proj4Leaflet#lprojgeojson
                        if (feature.geometry.crs) {
                            var crs = feature.geometry.crs;
                            if (crs.type == "link") {
                                var code = crs.properties.href.split("/").pop();
                                delete feature.geometry.crs;
                                delete crs.properties.href;
                                crs.type = "name";
                                crs.properties.name = "EPSG:" + code;
                                feature.crs = crs;
                            }
                        }
                        features.push(feature);
                    }
                }
                return {
                    type: "FeatureCollection",
                    features: features
                };
            }
        }
    };
});
<commit_msg>Get last map widget<commit_after>/**
 * @author Oscar Fonts <oscar.fonts@geomati.co>
 */
define(['SOS', 'leaflet', 'proj4', 'proj4leaflet', 'leaflet-label'], function(SOS, L, proj4) {

    proj4.defs("EPSG:23031", "+title= ED50 / UTM zone 31N +proj=utm +zone=31 +ellps=intl +units=m +no_defs +towgs84=-181.5,-90.3,-187.2,0.144,0.492,-0.394,17.57");

    var inputs = ["service", "offering", "features", "maxInitialZoom"];

    return {
        inputs: inputs,
        init: function(config, renderTo) {
            var map = L.map(renderTo, {
                dragging: false,
                touchZoom: false,
                scrollWheelZoom: false,
                doubleClickZoom: false,
                boxZoom: false,
                zoomControl: false
            }).setView([30, 0], 2);

            L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {
                subdomains: '1234',
                minZoom: 2,
                maxZoom: 14,
                attribution: 'OpenStreetMap | MapQuest'
            }).addTo(map);

            SOS.setUrl(config.service);
            read();

            function read() {
                SOS.getCapabilities(function(offerings) {
                    var addFoIs = function(features) {
                        var geojson = L.Proj.geoJson(fois2geojson(features), {
                            onEachFeature: function(feature, layer) {
                                if (feature.properties && feature.properties.name) {
                                    layer.bindLabel(feature.properties.name).addTo(map);
                                }
                            }
                        });
                        geojson.addTo(map);
                        map.fitBounds(geojson.getBounds(), {
                            maxZoom: config.maxInitialZoom ? parseInt(config.maxInitialZoom) : 14
                        });
                    };
                    for (var i in offerings) {
                        var offering = offerings[i];
                        if (offering.identifier == config.offering) {
                            SOS.getFeatureOfInterest(offering.procedure[0], addFoIs);
                        }
                    }
                });
            }

            function isArray(obj) {
                return Object.prototype.toString.call(obj) === '[object Array]';
            }

            function isInArray(value, array) {
                return array.indexOf(value) > -1;
            }

            function fois2geojson(fois) {
                var config_features = isArray(config.features) ? config.features : JSON.parse(config.features);
                var features = [];
                var crs = null;
                for (var i in fois) {
                    var foi = fois[i];
                    if (foi.geometry && (!config_features.length || isInArray(foi.identifier.value, config.features))) {
                        var feature = {
                            type: "Feature",
                            geometry: foi.geometry,
                            id: foi.identifier.value,
                            properties: {
                                name: foi.name.value
                            }
                        };
                        // Transform CRS from link type to name type.
                        // See spec: http://geojson.org/geojson-spec.html#named-crs
                        // See impl: https://github.com/kartena/Proj4Leaflet#lprojgeojson
                        // Assumes the same CRS for all FoIs!!
                        if (!crs && feature.geometry.crs) {
                            crs = feature.geometry.crs;
                            if (crs.type == "link") {
                                var code = crs.properties.href.split("/").pop();
                                delete crs.properties.href;
                                crs.type = "name";
                                crs.properties.name = "EPSG:" + code;
                            }
                        }
                        delete feature.geometry.crs;
                        features.push(feature);
                    }
                }
                var featureCollection = {
                    type: "FeatureCollection",
                    features: features
                };
                // Assign 'global' CRS to the whole FeatureCollection (top-level structure)
                if (crs) {
                    featureCollection.crs = crs;
                }
                return featureCollection;
            }
        }
    };
});
<|endoftext|>


<commit_before>#ifndef __lang_Function__
#define __lang_Function__

////////////////////////////////////////////////////////////////////////////////
// Function

#ifdef RHINO
if (!Function.prototype.$constructor) {
	// Override the function object with an implementation of a more efficient
	// Consctructor that creates properly generated functions instead of
	// interpretated ones. These are faster.
	// This does not seem to break anything, as afterward
	// Object.toString instanceof Function still returns true.
	Function = Function.extend({
		$constructor: function() {
			var args = $A(arguments), body = args.pop();
			var cx = Packages.org.mozilla.javascript.Context.getCurrentContext();
			return cx.compileFunction({}, "function (" + args + ") {" +
				body + "}", "Function", 0, null);
		}
	});
}
#endif // RHINO

Function.inject(function() {

#ifdef BROWSER
#ifdef BROWSER_LEGACY
	Function.timers = {};
	var timerId = 0;

#endif // BROWSER_LEGACY
	function timer(that, type, args, ms) {
		var fn = that.bind.apply(that, $A(args, 1));
#ifdef BROWSER_LEGACY
		var id = timerId++;
		Function.timers[id] = fn;
		var f = "Function.timers[" + id + "]", call = f + "();";
		// directly erase non-periodic timers
		if (type[0] == 'T') call += " delete " + f;
		var timer = window['set' + type](call, ms);
#else // !BROWSER_LEGACY
		var timer = window['set' + type](fn, ms);
#endif // !BROWSER_LEGACY
		fn.clear = function() {
			clearTimeout(timer);
			clearInterval(timer);
#ifdef BROWSER_LEGACY
			delete Function.timers[id];
#endif // BROWSER_LEGACY
		};
		return fn;
	}
#endif // BROWSER

	return {
		/**
		 * Returns the function's parameter names as an array
		 */
		parameters: function() {
			return this.toString().match(/^\s*function[^\(]*\(([^\)]*)/)[1].split(/\s*,\s*/);
		},

		/**
		 * Returns the function's body as a string, excluding the surrounding { }
		 */
		body: function() {
			return this.toString().match(/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1];
		},

#ifdef BROWSER
		delay: function(ms) {
			return timer(this, "Timeout", arguments, ms);
		},

		periodic: function(ms) {
			return timer(this, "Interval", arguments, ms);
		},
#endif // !BROWSER

		bind: function(obj) {
			var that = this, args = $A(arguments, 1);
			return function() {
				return that.apply(obj, args.concat($A(arguments)));
			}
		},

		attempt: function(obj) {
			var that = this, args = $A(arguments, 1);
			return function() {
				try { return that.apply(obj, args.concat($A(arguments))); }
				catch(e) { return e; }
			}
		}
	}
}, true);
// dontEnum these properties, as we iterate through Function.prototype in
// Function.prototype.inject

#ifdef BROWSER_LEGACY

////////////////////////////////////////////////////////////////////////////////
// Function Legacy

// Function.call / apply does not work properly on IE 5 PC / Mac

if (!Function.prototype.apply) {
	// never enum __f, the helper property introduced bellow
	Object.prototype.dontEnum(true, "__f");
	var cache = {};

	Function.inject({
		// = Ecma 1.5 apply/call at native speed, with variable argument count,
		// through caching of caller functions
		apply: function(obj, args, start) {
			if (!start) start = 0;
			// generate lookup slot name as integer for faster execution.
			// make room for a maximum of 64 arguments (start can be 0 or 1)
			var count = args ? args.length : 0, index = start * 64 + count;
			// use cached caller functions for the exact amount of parameters
			// like this, we prevent creation of argument lists each time.
			// only tehe first call is slower, everything that follows wit the
			// same amount of parameters should execute at almost native speed.
			var fn = cache[index];
			if (!fn) {
				fn = [];
				for (var i = start; i < count; i++)
					fn[i - start] = 'args[' + i + ']';
				fn = cache[index] = new Function('obj, args',
					'return obj.__f(' + fn + ');');
			}
			if (obj) {
				obj.__f = this;
				try { return fn(obj, args); }
				// delete on window object does not work on IE 5 PC
				finally { obj.__f = undefined; }
			} else {
				// this should be executed in window to be compliant, but
				// for some reasion, on MacIE execution there is much slower
				// than on an empty object. so do not rely on this to point
				// to the global scope when not set otherwise
				return fn({ __f: this }, args);
			}
		},

		call: function(obj) {
			return this.apply(obj, arguments, 1);
		}
	}, true);
}

#endif // BROWSER_LEGACY

#endif // __lang_Function__<commit_msg>Minor reformating.<commit_after>#ifndef __lang_Function__
#define __lang_Function__

////////////////////////////////////////////////////////////////////////////////
// Function

#ifdef RHINO
if (!Function.prototype.$constructor) {
	// Override the function object with an implementation of a more efficient
	// Consctructor that creates properly generated functions instead of
	// interpretated ones. These are faster.
	// This does not seem to break anything, as afterward
	// Object.toString instanceof Function still returns true.
	Function = Function.extend({
		$constructor: function() {
			var params = $A(arguments), body = params.pop();
			return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(
				{}, "function (" + params + ") {" + body + "}", "Function", 0, null);
		}
	});
}
#endif // RHINO

Function.inject(function() {

#ifdef BROWSER
#ifdef BROWSER_LEGACY
	Function.timers = {};
	var timerId = 0;

#endif // BROWSER_LEGACY
	function timer(that, type, args, ms) {
		var fn = that.bind.apply(that, $A(args, 1));
#ifdef BROWSER_LEGACY
		var id = timerId++;
		Function.timers[id] = fn;
		var f = "Function.timers[" + id + "]", call = f + "();";
		// directly erase non-periodic timers
		if (type[0] == 'T') call += " delete " + f;
		var timer = window['set' + type](call, ms);
#else // !BROWSER_LEGACY
		var timer = window['set' + type](fn, ms);
#endif // !BROWSER_LEGACY
		fn.clear = function() {
			clearTimeout(timer);
			clearInterval(timer);
#ifdef BROWSER_LEGACY
			delete Function.timers[id];
#endif // BROWSER_LEGACY
		};
		return fn;
	}
#endif // BROWSER

	return {
		/**
		 * Returns the function's parameter names as an array
		 */
		parameters: function() {
			return this.toString().match(/^\s*function[^\(]*\(([^\)]*)/)[1].split(/\s*,\s*/);
		},

		/**
		 * Returns the function's body as a string, excluding the surrounding { }
		 */
		body: function() {
			return this.toString().match(/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1];
		},

#ifdef BROWSER
		delay: function(ms) {
			return timer(this, "Timeout", arguments, ms);
		},

		periodic: function(ms) {
			return timer(this, "Interval", arguments, ms);
		},
#endif // !BROWSER

		bind: function(obj) {
			var that = this, args = $A(arguments, 1);
			return function() {
				return that.apply(obj, args.concat($A(arguments)));
			}
		},

		attempt: function(obj) {
			var that = this, args = $A(arguments, 1);
			return function() {
				try { return that.apply(obj, args.concat($A(arguments))); }
				catch(e) { return e; }
			}
		}
	}
}, true);
// dontEnum these properties, as we iterate through Function.prototype in
// Function.prototype.inject

#ifdef BROWSER_LEGACY

////////////////////////////////////////////////////////////////////////////////
// Function Legacy

// Function.call / apply does not work properly on IE 5 PC / Mac

if (!Function.prototype.apply) {
	// never enum __f, the helper property introduced bellow
	Object.prototype.dontEnum(true, "__f");
	var cache = {};

	Function.inject({
		// = Ecma 1.5 apply/call at native speed, with variable argument count,
		// through caching of caller functions
		apply: function(obj, args, start) {
			if (!start) start = 0;
			// generate lookup slot name as integer for faster execution.
			// make room for a maximum of 64 arguments (start can be 0 or 1)
			var count = args ? args.length : 0, index = start * 64 + count;
			// use cached caller functions for the exact amount of parameters
			// like this, we prevent creation of argument lists each time.
			// only tehe first call is slower, everything that follows wit the
			// same amount of parameters should execute at almost native speed.
			var fn = cache[index];
			if (!fn) {
				fn = [];
				for (var i = start; i < count; i++)
					fn[i - start] = 'args[' + i + ']';
				fn = cache[index] = new Function('obj, args',
					'return obj.__f(' + fn + ');');
			}
			if (obj) {
				obj.__f = this;
				try { return fn(obj, args); }
				// delete on window object does not work on IE 5 PC
				finally { obj.__f = undefined; }
			} else {
				// this should be executed in window to be compliant, but
				// for some reasion, on MacIE execution there is much slower
				// than on an empty object. so do not rely on this to point
				// to the global scope when not set otherwise
				return fn({ __f: this }, args);
			}
		},

		call: function(obj) {
			return this.apply(obj, arguments, 1);
		}
	}, true);
}

#endif // BROWSER_LEGACY

#endif // __lang_Function__<|endoftext|>


<commit_before>/*
Language: C++
Contributors: Evgeny Stepanischev <imbolk@gmail.com>
*/

hljs.LANGUAGES.cpp = function(){
  var CPP_KEYWORDS = {
    'keyword': {
      'false': 1, 'int': 1, 'float': 1, 'while': 1, 'private': 1, 'char': 1,
      'catch': 1, 'export': 1, 'virtual': 1, 'operator': 2, 'sizeof': 2,
      'dynamic_cast': 2, 'typedef': 2, 'const_cast': 2, 'const': 1,
      'struct': 1, 'for': 1, 'static_cast': 2, 'union': 1, 'namespace': 1,
      'unsigned': 1, 'long': 1, 'throw': 1, 'volatile': 2, 'static': 1,
      'protected': 1, 'bool': 1, 'template': 1, 'mutable': 1, 'if': 1,
      'public': 1, 'friend': 2, 'do': 1, 'return': 1, 'goto': 1, 'auto': 1,
      'void': 2, 'enum': 1, 'else': 1, 'break': 1, 'new': 1, 'extern': 1,
      'using': 1, 'true': 1, 'class': 1, 'asm': 1, 'case': 1, 'typeid': 1,
      'short': 1, 'reinterpret_cast': 2, 'default': 1, 'double': 1,
      'register': 1, 'explicit': 1, 'signed': 1, 'typename': 1, 'try': 1,
      'this': 1, 'switch': 1, 'continue': 1, 'wchar_t': 1, 'inline': 1,
      'delete': 1, 'alignof': 1, 'char16_t': 1, 'char32_t': 1, 'constexpr': 1,
      'decltype': 1, 'noexcept': 1, 'nullptr': 1, 'static_assert': 1,
      'thread_local': 1, 'restrict': 1
    },
    'built_in': {
      'std': 1, 'string': 1, 'cin': 1, 'cout': 1, 'cerr': 1, 'clog': 1,
      'stringstream': 1, 'istringstream': 1, 'ostringstream': 1, 'auto_ptr': 1,
      'deque': 1, 'list': 1, 'queue': 1, 'stack': 1, 'vector': 1, 'map': 1,
      'set': 1, 'bitset': 1, 'multiset': 1, 'multimap': 1, 'unordered_set': 1,
      'unordered_map': 1, 'unordered_multiset': 1, 'unordered_multimap': 1,
      'array': 1, 'shared_ptr': 1
    }
  };
  return {
    defaultMode: {
      keywords: CPP_KEYWORDS,
      illegal: '</',
      contains: [
        hljs.C_LINE_COMMENT_MODE,
        hljs.C_BLOCK_COMMENT_MODE,
        hljs.QUOTE_STRING_MODE,
        {
          className: 'string',
          begin: '\'\\\\?.', end: '\'',
          illegal: '.'
        },
        hljs.C_NUMBER_MODE,
        {
          className: 'preprocessor',
          begin: '#', end: '$'
        },
        {
          className: 'stl_container',
          begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<', end: '>',
          keywords: CPP_KEYWORDS,
          relevance: 10,
          contains: ['self']
        }
      ]
    }
  };
}();
<commit_msg>C99 new types: complex and _Bool<commit_after>/*
Language: C++
Contributors: Evgeny Stepanischev <imbolk@gmail.com>
*/

hljs.LANGUAGES.cpp = function(){
  var CPP_KEYWORDS = {
    'keyword': {
      'false': 1, 'int': 1, 'float': 1, 'while': 1, 'private': 1, 'char': 1,
      'catch': 1, 'export': 1, 'virtual': 1, 'operator': 2, 'sizeof': 2,
      'dynamic_cast': 2, 'typedef': 2, 'const_cast': 2, 'const': 1,
      'struct': 1, 'for': 1, 'static_cast': 2, 'union': 1, 'namespace': 1,
      'unsigned': 1, 'long': 1, 'throw': 1, 'volatile': 2, 'static': 1,
      'protected': 1, 'bool': 1, 'template': 1, 'mutable': 1, 'if': 1,
      'public': 1, 'friend': 2, 'do': 1, 'return': 1, 'goto': 1, 'auto': 1,
      'void': 2, 'enum': 1, 'else': 1, 'break': 1, 'new': 1, 'extern': 1,
      'using': 1, 'true': 1, 'class': 1, 'asm': 1, 'case': 1, 'typeid': 1,
      'short': 1, 'reinterpret_cast': 2, 'default': 1, 'double': 1,
      'register': 1, 'explicit': 1, 'signed': 1, 'typename': 1, 'try': 1,
      'this': 1, 'switch': 1, 'continue': 1, 'wchar_t': 1, 'inline': 1,
      'delete': 1, 'alignof': 1, 'char16_t': 1, 'char32_t': 1, 'constexpr': 1,
      'decltype': 1, 'noexcept': 1, 'nullptr': 1, 'static_assert': 1,
      'thread_local': 1, 'restrict': 1, '_Bool':1, 'complex': 1
    },
    'built_in': {
      'std': 1, 'string': 1, 'cin': 1, 'cout': 1, 'cerr': 1, 'clog': 1,
      'stringstream': 1, 'istringstream': 1, 'ostringstream': 1, 'auto_ptr': 1,
      'deque': 1, 'list': 1, 'queue': 1, 'stack': 1, 'vector': 1, 'map': 1,
      'set': 1, 'bitset': 1, 'multiset': 1, 'multimap': 1, 'unordered_set': 1,
      'unordered_map': 1, 'unordered_multiset': 1, 'unordered_multimap': 1,
      'array': 1, 'shared_ptr': 1
    }
  };
  return {
    defaultMode: {
      keywords: CPP_KEYWORDS,
      illegal: '</',
      contains: [
        hljs.C_LINE_COMMENT_MODE,
        hljs.C_BLOCK_COMMENT_MODE,
        hljs.QUOTE_STRING_MODE,
        {
          className: 'string',
          begin: '\'\\\\?.', end: '\'',
          illegal: '.'
        },
        hljs.C_NUMBER_MODE,
        {
          className: 'preprocessor',
          begin: '#', end: '$'
        },
        {
          className: 'stl_container',
          begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<', end: '>',
          keywords: CPP_KEYWORDS,
          relevance: 10,
          contains: ['self']
        }
      ]
    }
  };
}();
<|endoftext|>