<commit_before>/**
 * @todo don't show last/first week twice across two consecutive months
 * @todo smart-zoom (1 mo, 3 mo, 6mo, > 6mo)
 * @todo if there are 4 months => display 6 months. figure out how to display those 2 extra months
 */

import Ember from 'ember';
import layout from '../templates/components/calendar-month-multi';

const {
  computed,
  on
} = Ember;

const Month = Ember.Object.extend({
  month: null,
  year: null,

  /**
   * Show last partial week
   * If current month ends on a Tuesday, don't show this month on this calendar, but rather the next month
   * This should be true for the last month
   * @todo verify this works
   * @type {Boolean}
   */
  showLastPartialWeek: false
})

export default Ember.Component.extend({
  layout,
  classNames: ['calendar-month-multi'],

  // canonical
  startDate: null,
  endDate: null,

  context: null,

  /**
   * Max months to show
   * @type {Number}
   */
  maxMonthsToShow: 6,

  _onDidReceiveAttrs: on('didReceiveAttrs', function() {
    // validate starDate and endDate are valid moment objects
    if (!moment.isMoment(this.get('startDate')) || !moment.isMoment(this.get('endDate'))) {
      this.setProperties({
        startDate: moment(this.get('startDate')),
        endDate: moment(this.get('endDate'))
      });
    }

    // validate startDate is before endDate
    if (this.get('endDate').isBefore(this.get('startDate'))) {
      throw new Error('Start date must be before end date', this.get('startDate'), this.get('endDate'));
    }
  }),

  /**
   * Override this method in your controller
   * @param {object} date - moment date
   * @return {string} class name to be applied to this date
   */
  customClassFunction(date) {
    return false;
  },

  /**
   * Don't show duplicate end of last month/beginning of this month
   * If endDate - startDate = 2 months, still display 3 months (pad one on end)
   * If endDate - startDate > 6 mo, display "next" and "previous"
   * @type {array} array of months
   */
  displayMonths: computed('startDate', 'endDate', 'numberOfMonthsToDisplay', function() {
    var months = [];
    let current = moment(this.get('startDate'));

    for (let i = 0; i < this.get('numberOfMonthsToDisplay'); i++) {
        months.addObject(Month.create({
          // current.month() is 0-indexed, but calendar-month expects 1-indexed month
          month: current.month(),
          year: current.year(),
          showLastPartialWeek: (i === this.get('numberOfMonthsToDisplay') - 1)
        }));
        current.add(1, 'month');
    }

    return months;
  }),

  /**
   * The number of months to display
   * @type {number}
   */
  numberOfMonthsToDisplay: computed('startDate', 'endDate', 'maxMonthsToShow', function() {
    var startDate = this.get('startDate');
    var endDate = this.get('endDate');
    const maxMonthsToShow = this.get('maxMonthsToShow');

    if (startDate.month() === endDate.month()) {
      return 1;
    }

    var monthsDiff = endDate.diff(startDate, 'months');

    if (monthsDiff > maxMonthsToShow) {
      return maxMonthsToShow;
    }

    return monthsDiff;
  })
});
<commit_msg>add 1 to `numberOfMonthsToDisplay` so it is inclusive<commit_after>/**
 * @todo don't show last/first week twice across two consecutive months
 * @todo smart-zoom (1 mo, 3 mo, 6mo, > 6mo)
 * @todo if there are 4 months => display 6 months. figure out how to display those 2 extra months
 */

import Ember from 'ember';
import layout from '../templates/components/calendar-month-multi';

const {
  computed,
  on
} = Ember;

const Month = Ember.Object.extend({
  month: null,
  year: null,

  /**
   * Show last partial week
   * If current month ends on a Tuesday, don't show this month on this calendar, but rather the next month
   * This should be true for the last month
   * @todo verify this works
   * @type {Boolean}
   */
  showLastPartialWeek: false
})

export default Ember.Component.extend({
  layout,
  classNames: ['calendar-month-multi'],

  // canonical
  startDate: null,
  endDate: null,

  context: null,

  /**
   * Max months to show
   * @type {Number}
   */
  maxMonthsToShow: 6,

  _onDidReceiveAttrs: on('didReceiveAttrs', function() {
    // validate starDate and endDate are valid moment objects
    if (!moment.isMoment(this.get('startDate')) || !moment.isMoment(this.get('endDate'))) {
      this.setProperties({
        startDate: moment(this.get('startDate')),
        endDate: moment(this.get('endDate'))
      });
    }

    // validate startDate is before endDate
    if (this.get('endDate').isBefore(this.get('startDate'))) {
      throw new Error('Start date must be before end date', this.get('startDate'), this.get('endDate'));
    }
  }),

  /**
   * Override this method in your controller
   * @param {object} date - moment date
   * @return {string} class name to be applied to this date
   */
  customClassFunction(date) {
    return false;
  },

  /**
   * Don't show duplicate end of last month/beginning of this month
   * If endDate - startDate = 2 months, still display 3 months (pad one on end)
   * If endDate - startDate > 6 mo, display "next" and "previous"
   * @type {array} array of months
   */
  displayMonths: computed('startDate', 'endDate', 'numberOfMonthsToDisplay', function() {
    var months = [];
    let current = moment(this.get('startDate'));

    for (let i = 0; i < this.get('numberOfMonthsToDisplay'); i++) {
        months.addObject(Month.create({
          // current.month() is 0-indexed, but calendar-month expects 1-indexed month
          month: current.month(),
          year: current.year(),
          showLastPartialWeek: (i === this.get('numberOfMonthsToDisplay') - 1)
        }));
        current.add(1, 'month');
    }

    return months;
  }),

  /**
   * The number of months to display
   * @type {number}
   */
  numberOfMonthsToDisplay: computed('startDate', 'endDate', 'maxMonthsToShow', function() {
    var startDate = this.get('startDate');
    var endDate = this.get('endDate');
    const maxMonthsToShow = this.get('maxMonthsToShow');

    if (startDate.month() === endDate.month()) {
      return 1;
    }

    var monthsDiff = endDate.diff(startDate, 'months');

    if (monthsDiff > maxMonthsToShow) {
      return maxMonthsToShow;
    }

    return monthsDiff + 1;
  })
});
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2017 kuniaki.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

module.exports = {
    mode: "development",
    entry:
            {
                "ArduinoCOMWSTest": './ArduinoCOMWSTest.ts',
                "DefiCOMWSTest": './DefiCOMWSTest.ts',
                "ELM327COMWSTest": './ELM327COMWSTest.ts',
                "SSMCOMWSTest": './SSMCOMWSTest.ts',
                "FUELTRIPWSTest": './FUELTRIPWSTest.ts',
                "DefiCOMWSInterpolateTest": './DefiCOMWSInterpolateTest.ts',
                "AssettoCorsaSHMWSTest": './AssettoCorsaSHMWSTest.ts'
            },
    devtool: "source-map",
    output:
            {
                path: __dirname + "/../../public_html/WebSocketTester/",
                filename: "js/[name].js"
            },
    resolve: {
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: ['.webpack.js', '.web.js', '.ts', '.tsx', '.js']
    },
    module: {
        rules: [
            // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
            {test: /\.tsx?$/, loader: 'ts-loader'},
            {test: /\.html$/, loader: "file-loader?name=[name].[ext]"}
        ]
    }
};
<commit_msg>Fix rules of webpack.config.js to avoid webpack error.<commit_after>/*
 * The MIT License
 *
 * Copyright 2017 kuniaki.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

module.exports = {
    mode: "development",
    entry:
            {
                "ArduinoCOMWSTest": './ArduinoCOMWSTest.ts',
                "DefiCOMWSTest": './DefiCOMWSTest.ts',
                "ELM327COMWSTest": './ELM327COMWSTest.ts',
                "SSMCOMWSTest": './SSMCOMWSTest.ts',
                "FUELTRIPWSTest": './FUELTRIPWSTest.ts',
                "DefiCOMWSInterpolateTest": './DefiCOMWSInterpolateTest.ts',
                "AssettoCorsaSHMWSTest": './AssettoCorsaSHMWSTest.ts'
            },
    devtool: "source-map",
    output:
            {
                path: __dirname + "/../../public_html/WebSocketTester/",
                filename: "js/[name].js"
            },
    resolve: {
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: ['.webpack.js', '.web.js', '.ts', '.tsx', '.js']
    },
    module: {
        rules: [
            // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
            {test: /\.tsx?$/, use :["style-loader", {loader: 'ts-loader'}]},
            {test: /\.html$/, use : ["file-loader", {loader: "file-loader?name=[name].[ext]"}]}
        ]
    }
};
<|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var tape = require( 'tape' );
var isNonNegativeInteger = require( '@stdlib/math/base/assert/is-nonnegative-integer' );
var isUint32Array = require( '@stdlib/assert/is-uint32array' );
var uniform = require( '@stdlib/random/base/uniform' ).factory;
var poisson = require( './../lib' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof poisson, 'function', 'main export is a function' );
	t.end();
});

tape( 'attached to the main export is a method to generate pseudorandom number generators', function test( t ) {
	t.equal( typeof poisson.factory, 'function', 'has `factory` method' );
	t.end();
});

tape( 'attached to the main export is the generator name', function test( t ) {
	t.equal( poisson.NAME, 'poisson', 'has `NAME` property' );
	t.end();
});

tape( 'attached to the main export is the underlying PRNG', function test( t ) {
	t.equal( typeof poisson.PRNG, 'function', 'has `PRNG` property' );
	t.end();
});

tape( 'attached to the main export is the generator seed', function test( t ) {
	t.equal( isUint32Array( poisson.seed ), true, 'has `seed` property' );
	t.end();
});

tape( 'the function returns pseudorandom numbers', function test( t ) {
	var randu;
	var r;
	var i;

	randu = uniform( 0.00000001, 10000.0 );
	for ( i = 0; i < 1e3; i++ ) {
		r = poisson( randu() );
		t.strictEqual( isNonNegativeInteger( r ), true, 'returns a nonnegative integer' );
	}
	t.end();
});
<commit_msg>Update tests<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var tape = require( 'tape' );
var isNonNegativeInteger = require( '@stdlib/math/base/assert/is-nonnegative-integer' );
var isUint32Array = require( '@stdlib/assert/is-uint32array' );
var uniform = require( '@stdlib/random/base/uniform' ).factory;
var poisson = require( './../lib' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof poisson, 'function', 'main export is a function' );
	t.end();
});

tape( 'attached to the main export is a method to generate pseudorandom number generators', function test( t ) {
	t.equal( typeof poisson.factory, 'function', 'has method' );
	t.end();
});

tape( 'attached to the main export is the generator name', function test( t ) {
	t.equal( poisson.NAME, 'poisson', 'has property' );
	t.end();
});

tape( 'attached to the main export is the underlying PRNG', function test( t ) {
	t.equal( typeof poisson.PRNG, 'function', 'has property' );
	t.end();
});

tape( 'attached to the main export is the generator seed', function test( t ) {
	t.equal( isUint32Array( poisson.seed ), true, 'has property' );
	t.end();
});

tape( 'attached to the main export is the generator seed length', function test( t ) {
	t.equal( typeof poisson.seedLength, 'number', 'has property' );
	t.end();
});

tape( 'attached to the main export is the generator state', function test( t ) {
	t.equal( isUint32Array( poisson.state ), true, 'has property' );
	t.end();
});

tape( 'attached to the main export is the generator state length', function test( t ) {
	t.equal( typeof poisson.stateLength, 'number', 'has property' );
	t.end();
});

tape( 'attached to the main export is the generator state size', function test( t ) {
	t.equal( typeof poisson.byteLength, 'number', 'has property' );
	t.end();
});

tape( 'the function returns pseudorandom numbers', function test( t ) {
	var randu;
	var r;
	var i;

	randu = uniform( 0.00000001, 10000.0 );
	for ( i = 0; i < 1e3; i++ ) {
		r = poisson( randu() );
		t.strictEqual( isNonNegativeInteger( r ), true, 'returns a nonnegative integer' );
	}
	t.end();
});

tape( 'the function supports setting the generator state', function test( t ) {
	var state;
	var arr;
	var i;

	// Move to a future state...
	for ( i = 0; i < 100; i++ ) {
		poisson( 10.0 );
	}
	// Capture the current state:
	state = poisson.state;

	// Move to a future state...
	arr = [];
	for ( i = 0; i < 100; i++ ) {
		arr.push( poisson( 10.0 ) );
	}
	// Set the state:
	poisson.state = state;

	// Replay previously generated values...
	for ( i = 0; i < 100; i++ ) {
		t.equal( poisson( 10.0 ), arr[ i ], 'returns expected value. i: '+i+'.' );
	}
	t.end();
});
<|endoftext|>


<commit_before>var windows8 = require('../../src/platforms/windows8'),
    common  = require('../../src/platforms/common'),
    install = require('../../src/install'),
    path    = require('path'),
    fs      = require('fs'),
    shell   = require('shelljs'),
    et      = require('elementtree'),
    os      = require('osenv'),
    temp    = path.join(os.tmpdir(), 'plugman'),
    plugins_dir = path.join(temp, 'cordova', 'plugins'),
    xml_helpers = require('../../src/util/xml-helpers'),
    plugins_module = require('../../src/util/plugins'),
    dummyplugin = path.join(__dirname, '..', 'plugins', 'DummyPlugin'),
    faultyplugin = path.join(__dirname, '..', 'plugins', 'FaultyPlugin'),
    windows8_project = path.join(__dirname, '..', 'projects', 'windows8');

var xml_path     = path.join(dummyplugin, 'plugin.xml')
  , xml_text     = fs.readFileSync(xml_path, 'utf-8')
  , plugin_et    = new et.ElementTree(et.XML(xml_text));

var platformTag = plugin_et.find('./platform[@name="windows8"]');
var dummy_id = plugin_et._root.attrib['id'];

var valid_source = platformTag.findall('./source-file');
var assets = plugin_et.findall('./asset');

var configChanges = platformTag.findall('./config-file');

xml_path  = path.join(faultyplugin, 'plugin.xml')
xml_text  = fs.readFileSync(xml_path, 'utf-8');

plugin_et = new et.ElementTree(et.XML(xml_text));

platformTag = plugin_et.find('./platform[@name="windows8"]');

var invalid_source = platformTag.findall('./source-file');

var faulty_id = plugin_et._root.attrib['id'];

shell.mkdir('-p', temp);
shell.cp('-rf', path.join(windows8_project, '*'), temp);
var proj_files = windows8.parseProjectFile(temp);
shell.rm('-rf', temp);

function copyArray(arr) {
    return Array.prototype.slice.call(arr, 0);
}

describe('windows8 project handler', function() {

    beforeEach(function() {
        shell.mkdir('-p', temp);
        shell.mkdir('-p', plugins_dir);
    });
    afterEach(function() {
        shell.rm('-rf', temp);
    });

    describe('www_dir method', function() {
        it('should return cordova-windows8 project www location using www_dir', function() {
            expect(windows8.www_dir(path.sep)).toEqual(path.sep + 'www');
        });
    });
    describe('package_name method', function() {
        it('should return a windows8 project\'s proper package name', function() {
            expect(windows8.package_name(windows8_project)).toEqual("CordovaApp");
        });
    });

    describe('parseProjectFile method', function() {
        it('should throw if project is not an windows8 project', function() {
            expect(function() {
                windows8.parseProjectFile(temp);
            }).toThrow(windows8.InvalidProjectPathError);
        });
    });

    describe('installation', function() {
        beforeEach(function() {
            shell.mkdir('-p', temp);
        });
        afterEach(function() {
            shell.rm('-rf', temp);
        });
        describe('of <source-file> elements', function() {
            beforeEach(function() {
                shell.cp('-rf', path.join(windows8_project, '*'), temp);
            });
            it('should copy stuff from one location to another by calling common.copyFile', function() {
                var source = copyArray(valid_source);
                var s = spyOn(common, 'copyFile');
                windows8['source-file'].install(source[0], dummyplugin, temp, dummy_id, proj_files);
                expect(s).toHaveBeenCalledWith(dummyplugin, 'src/windows8/dummer.js', temp, path.join('Plugins', 'com.phonegap.plugins.dummyplugin', 'dummer.js'));
            });
            it('should throw if source-file src cannot be found', function() {
                var source = copyArray(invalid_source);
                expect(function() {
                    windows8['source-file'].install(source[1], faultyplugin, temp, faulty_id, proj_files);
                }).toThrow('"' + path.resolve(faultyplugin, 'src/windows8/NotHere.js') + '" not found!');
            });
            it('should throw if source-file target already exists', function() {
                var source = copyArray(valid_source);
                var target = path.join(temp, 'Plugins', dummy_id, 'dummer.js');
                shell.mkdir('-p', path.dirname(target));
                fs.writeFileSync(target, 'some bs', 'utf-8');
                expect(function() {
                    windows8['source-file'].install(source[0], dummyplugin, temp, dummy_id, proj_files);
                }).toThrow('"' + target + '" already exists!');
            });
        });
    });

    describe('uninstallation', function() {
        beforeEach(function() {
            shell.mkdir('-p', temp);
            shell.mkdir('-p', plugins_dir);
            shell.cp('-rf', path.join(windows8_project, '*'), temp);
        });
        afterEach(function() {
            shell.rm('-rf', temp);
        });
        describe('of <source-file> elements', function() {
            it('should remove stuff by calling common.removeFile', function(done) {
                var s = spyOn(common, 'removeFile');
                install('windows8', temp, dummyplugin, plugins_dir, {}, function() {
                    var source = copyArray(valid_source);
                    windows8['source-file'].uninstall(source[0], temp, dummy_id, proj_files);
                    expect(s).toHaveBeenCalledWith(temp, path.join('Plugins', 'com.phonegap.plugins.dummyplugin', 'dummer.js'));
                    done();
                });
            });
        });
    });
});
<commit_msg>fix windows8 tests<commit_after>var windows8 = require('../../src/platforms/windows8'),
    common  = require('../../src/platforms/common'),
    install = require('../../src/install'),
    path    = require('path'),
    fs      = require('fs'),
    shell   = require('shelljs'),
    et      = require('elementtree'),
    os      = require('osenv'),
    temp    = path.join(os.tmpdir(), 'plugman'),
    plugins_dir = path.join(temp, 'cordova', 'plugins'),
    xml_helpers = require('../../src/util/xml-helpers'),
    plugins_module = require('../../src/util/plugins'),
    dummyplugin = path.join(__dirname, '..', 'plugins', 'DummyPlugin'),
    faultyplugin = path.join(__dirname, '..', 'plugins', 'FaultyPlugin'),
    windows8_project = path.join(__dirname, '..', 'projects', 'windows8');

var xml_path     = path.join(dummyplugin, 'plugin.xml')
  , xml_text     = fs.readFileSync(xml_path, 'utf-8')
  , plugin_et    = new et.ElementTree(et.XML(xml_text));

var platformTag = plugin_et.find('./platform[@name="windows8"]');
var dummy_id = plugin_et._root.attrib['id'];

var valid_source = platformTag.findall('./source-file');
var assets = plugin_et.findall('./asset');

var configChanges = platformTag.findall('./config-file');

xml_path  = path.join(faultyplugin, 'plugin.xml')
xml_text  = fs.readFileSync(xml_path, 'utf-8');

plugin_et = new et.ElementTree(et.XML(xml_text));

platformTag = plugin_et.find('./platform[@name="windows8"]');

var invalid_source = platformTag.findall('./source-file');

var faulty_id = plugin_et._root.attrib['id'];

shell.mkdir('-p', temp);
shell.cp('-rf', path.join(windows8_project, '*'), temp);
var proj_files = windows8.parseProjectFile(temp);
shell.rm('-rf', temp);

function copyArray(arr) {
    return Array.prototype.slice.call(arr, 0);
}

describe('windows8 project handler', function() {

    beforeEach(function() {
        shell.mkdir('-p', temp);
        shell.mkdir('-p', plugins_dir);
    });
    afterEach(function() {
        shell.rm('-rf', temp);
    });

    describe('www_dir method', function() {
        it('should return cordova-windows8 project www location using www_dir', function() {
            expect(windows8.www_dir(path.sep)).toEqual(path.sep + 'www');
        });
    });
    describe('package_name method', function() {
        it('should return a windows8 project\'s proper package name', function() {
            expect(windows8.package_name(windows8_project)).toEqual("CordovaApp");
        });
    });

    describe('parseProjectFile method', function() {
        it('should throw if project is not an windows8 project', function() {
            expect(function() {
                windows8.parseProjectFile(temp);
            }).toThrow(windows8.InvalidProjectPathError);
        });
    });

    describe('installation', function() {
        beforeEach(function() {
            shell.mkdir('-p', temp);
        });
        afterEach(function() {
            shell.rm('-rf', temp);
        });
        describe('of <source-file> elements', function() {
            beforeEach(function() {
                shell.cp('-rf', path.join(windows8_project, '*'), temp);
            });
            it('should copy stuff from one location to another by calling common.copyFile', function() {
                var source = copyArray(valid_source);
                var s = spyOn(common, 'copyFile');
                windows8['source-file'].install(source[0], dummyplugin, temp, dummy_id, proj_files);
                expect(s).toHaveBeenCalledWith(dummyplugin, 'src/windows8/dummer.js', temp, path.join('www', 'plugins', 'com.phonegap.plugins.dummyplugin', 'dummer.js'));
            });
            it('should throw if source-file src cannot be found', function() {
                var source = copyArray(invalid_source);
                expect(function() {
                    windows8['source-file'].install(source[1], faultyplugin, temp, faulty_id, proj_files);
                }).toThrow('"' + path.resolve(faultyplugin, 'src/windows8/NotHere.js') + '" not found!');
            });
            it('should throw if source-file target already exists', function() {
                var source = copyArray(valid_source);
                var target = path.join(temp, 'www', 'plugins', dummy_id, 'dummer.js');
                shell.mkdir('-p', path.dirname(target));
                fs.writeFileSync(target, 'some bs', 'utf-8');
                expect(function() {
                    windows8['source-file'].install(source[0], dummyplugin, temp, dummy_id, proj_files);
                }).toThrow('"' + target + '" already exists!');
            });
        });
    });

    describe('uninstallation', function() {
        beforeEach(function() {
            shell.mkdir('-p', temp);
            shell.mkdir('-p', plugins_dir);
            shell.cp('-rf', path.join(windows8_project, '*'), temp);
        });
        afterEach(function() {
            shell.rm('-rf', temp);
        });
        describe('of <source-file> elements', function() {
            it('should remove stuff by calling common.removeFile', function(done) {
                var s = spyOn(common, 'removeFile');
                install('windows8', temp, dummyplugin, plugins_dir, {}, function() {
                    var source = copyArray(valid_source);
                    windows8['source-file'].uninstall(source[0], temp, dummy_id, proj_files);
                    expect(s).toHaveBeenCalledWith(temp, path.join('www', 'plugins',  'com.phonegap.plugins.dummyplugin', 'dummer.js'));
                    done();
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>function getter(instance, path, unboundFn) {
  if (!path) return instance;
  var element = path.split('.');
  var key;
  var lastInstance = instance;
  var len = element.length;
  for ( var i = 0; i < len; i++) {
    key = element[i];
    if (!key.match(/^[\$\w][\$\w\d]*$/))
        throw "Expression '" + path + "' is not a valid expression for accesing variables.";
    if (instance) {
      lastInstance = instance;
      instance = instance[key];
    }
    if (isUndefined(instance)  && key.charAt(0) == '$') {
      var type = angular['Global']['typeOf'](lastInstance);
      type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
      var fn = type ? type[[key.substring(1)]] : _undefined;
      if (fn) {
        instance = bind(lastInstance, fn, lastInstance);
        return instance;
      }
    }
  }
  if (!unboundFn && isFunction(instance)) {
    return bind(lastInstance, instance);
  }
  return instance;
}

function setter(instance, path, value){
  var element = path.split('.');
  for ( var i = 0; element.length > 1; i++) {
    var key = element.shift();
    var newInstance = instance[key];
    if (!newInstance) {
      newInstance = {};
      instance[key] = newInstance;
    }
    instance = newInstance;
  }
  instance[element.shift()] = value;
  return value;
}

///////////////////////////////////
var scopeId = 0,
    getterFnCache = {},
    compileCache = {},
    JS_KEYWORDS = {};
foreach(
    ("abstract,boolean,break,byte,case,catch,char,class,const,continue,debugger,default," +
    "delete,do,double,else,enum,export,extends,false,final,finally,float,for,function,goto," +
    "if,implements,import,ininstanceof,intinterface,long,native,new,null,package,private," +
    "protected,public,return,short,static,super,switch,synchronized,this,throw,throws," +
    "transient,true,try,typeof,var,volatile,void,undefined,while,with").split(/,/),
  function(key){ JS_KEYWORDS[key] = true;}
);
function getterFn(path){
  var fn = getterFnCache[path];
  if (fn) return fn;

  var code = 'var l, fn, t;\n';
  foreach(path.split('.'), function(key) {
    key = (JS_KEYWORDS[key]) ? '["' + key + '"]' : '.' + key;
    code += 'if(!s) return s;\n' +
            'l=s;\n' +
            's=s' + key + ';\n' +
            'if(typeof s=="function") s = function(){ return l'+key+'.apply(l, arguments); };\n';
    if (key.charAt(1) == '$') {
      // special code for super-imposed functions
      var name = key.substr(2);
      code += 'if(!s) {\n' +
              '  t = angular.Global.typeOf(l);\n' +
              '  fn = (angular[t.charAt(0).toUpperCase() + t.substring(1)]||{})["' + name + '"];\n' +
              '  if (fn) s = function(){ return fn.apply(l, [l].concat(Array.prototype.slice.call(arguments, 0, arguments.length))); };\n' +
              '}\n';
    }
  });
  code += 'return s;';
  fn = Function('s', code);
  fn["toString"] = function(){ return code; };

  return getterFnCache[path] = fn;
}

///////////////////////////////////

function expressionCompile(exp){
  if (typeof exp === $function) return exp;
  var fn = compileCache[exp];
  if (!fn) {
    var p = parser(exp);
    var fnSelf = p.statements();
    p.assertAllConsumed();
    fn = compileCache[exp] = extend(
      function(){ return fnSelf(this);},
      {fnSelf: fnSelf});
  }
  return fn;
}

function errorHandlerFor(element, error) {
  elementError(element, NG_EXCEPTION, isDefined(error) ? formatError(error) : error);
}

function createScope(parent, providers, instanceCache) {
  function Parent(){}
  parent = Parent.prototype = (parent || {});
  var instance = new Parent();
  var evalLists = {sorted:[]};
  var postList = [], postHash = {}, postId = 0;

  extend(instance, {
    'this': instance,
    $id: (scopeId++),
    $parent: parent,
    $bind: bind(instance, bind, instance),
    $get: bind(instance, getter, instance),
    $set: bind(instance, setter, instance),

    $eval: function $eval(exp) {
      var type = typeof exp;
      var i, iSize;
      var j, jSize;
      var queue;
      var fn;
      if (type == $undefined) {
        for ( i = 0, iSize = evalLists.sorted.length; i < iSize; i++) {
          for ( queue = evalLists.sorted[i],
              jSize = queue.length,
              j= 0; j < jSize; j++) {
            instance.$tryEval(queue[j].fn, queue[j].handler);
          }
        }
        while(postList.length) {
          fn = postList.shift();
          delete postHash[fn.$postEvalId];
          instance.$tryEval(fn);
        }
      } else if (type === $function) {
        return exp.call(instance);
      } else  if (type === 'string') {
        return expressionCompile(exp).call(instance);
      }
    },

    $tryEval: function (expression, exceptionHandler) {
      var type = typeof expression;
      try {
        if (type == $function) {
          return expression.call(instance);
        } else if (type == 'string'){
          return expressionCompile(expression).call(instance);
        }
      } catch (e) {
        (instance.$log || {error:error}).error(e);
        if (isFunction(exceptionHandler)) {
          exceptionHandler(e);
        } else if (exceptionHandler) {
          errorHandlerFor(exceptionHandler, e);
        } else if (isFunction(instance.$exceptionHandler)) {
          instance.$exceptionHandler(e);
        }
      }
    },

    /**
     * @ngdoc
     * @name angular.scope#$watch
     * @function
     *
     * @description
     * Registers `listener` as a callback to be executed every time the `watchExp` changes. Be aware
     * that callback gets, by default, called upon registration, this can be prevented via the
     * `initRun` parameter.
     *
     * @param {Function|string} watchExp Expression that should be evaluated and checked for change
     *    during each eval cycle. Can be an angular string expression or a function.
     * @param {Function|string} listener Function (or angular string expression) that gets called
     *    every time the value of the `watchExp` changes. The function will be called with two
     *    parameters, `newValue` and `oldValue`.
     * @param {(Function|DOMElement)=} [exceptionHanlder=angular.service.$exceptionHandler] Handler
     *    that gets called when `watchExp` or `listener` throws an exception. If a DOMElement is
     *    specified as handler, the element gets decorated by angular with the information about the
     *    exception.
     * @param {boolean=} [initRun=true] Flag that prevents the first execution of the listener upon
     *    registration.
     *
     * @example

     */
    $watch: function(watchExp, listener, exceptionHandler, initRun) {
      var watch = expressionCompile(watchExp),
          last = watch.call(instance);
      listener = expressionCompile(listener);
      function watcher(firstRun){
        var value = watch.call(instance),
            // we have to save the value because listener can call ourselves => inf loop
            lastValue = last;
        if (firstRun || lastValue !== value) {
          last = value;
          instance.$tryEval(function(){
            return listener.call(instance, value, lastValue);
          }, exceptionHandler);
        }
      }
      instance.$onEval(PRIORITY_WATCH, watcher);
      if (isUndefined(initRun)) initRun = true;
      if (initRun) watcher(true);
    },

    $onEval: function(priority, expr, exceptionHandler){
      if (!isNumber(priority)) {
        exceptionHandler = expr;
        expr = priority;
        priority = 0;
      }
      var evalList = evalLists[priority];
      if (!evalList) {
        evalList = evalLists[priority] = [];
        evalList.priority = priority;
        evalLists.sorted.push(evalList);
        evalLists.sorted.sort(function(a,b){return a.priority-b.priority;});
      }
      evalList.push({
        fn: expressionCompile(expr),
        handler: exceptionHandler
      });
    },

    $postEval: function(expr) {
      if (expr) {
        var fn = expressionCompile(expr);
        var id = fn.$postEvalId;
        if (!id) {
          id = '$' + instance.$id + "_" + (postId++);
          fn.$postEvalId = id;
        }
        if (!postHash[id]) {
          postList.push(postHash[id] = fn);
        }
      }
    },

    /**
       @ngdoc
       @name angular.scope#$become
       @function
       @deprecated This method will be removed before 1.0

       @description
       Modifies the scope to act like an instance of the given class by:

       - copying the class's prototype methods
       - applying the class's initialization function to the scope instance (without using the new
         operator)
       -

       That makes the scope be a `this` for the given class's methods — effectively an instance of
       the given class with additional (scope) stuff. A scope can later `$become` another class.

       `$become` gets used to make the current scope act like an instance of a controller class.
       This allows for use of a controller class in two ways.

       - as an ordinary JavaScript class for standalone testing, instantiated using the new
         operator, with no attached view.
       - as a controller for an angular model stored in a scope, "instantiated" by
         `scope.$become(ControllerClass)`.

       Either way, the controller's methods refer to the model  variables like `this.name`. When
       stored in a scope, the model supports data binding. When bound to a view, {{name}} in the
       HTML template refers to the same variable.
     */
    $become: function(Class) {
      if (isFunction(Class)) {
        instance.constructor = Class;
        foreach(Class.prototype, function(fn, name){
          instance[name] = bind(instance, fn);
        });
        instance.$inject.apply(instance, concat([Class, instance], arguments, 1));

        //TODO: backwards compatibility hack, remove when we don't depend on init methods
        if (isFunction(Class.prototype.init)) {
          instance.init();
        }
      }
    },

    $new: function(Class) {
      var child = createScope(instance);
      child.$become.apply(instance, concat([Class], arguments, 1));
      instance.$onEval(child.$eval);
      return child;
    }

  });

  if (!parent.$root) {
    instance.$root = instance;
    instance.$parent = instance;
    (instance.$inject = createInjector(instance, providers, instanceCache))();
  }

  return instance;
}
<commit_msg>most of the documentation for angular.scope and friends<commit_after>function getter(instance, path, unboundFn) {
  if (!path) return instance;
  var element = path.split('.');
  var key;
  var lastInstance = instance;
  var len = element.length;
  for ( var i = 0; i < len; i++) {
    key = element[i];
    if (!key.match(/^[\$\w][\$\w\d]*$/))
        throw "Expression '" + path + "' is not a valid expression for accesing variables.";
    if (instance) {
      lastInstance = instance;
      instance = instance[key];
    }
    if (isUndefined(instance)  && key.charAt(0) == '$') {
      var type = angular['Global']['typeOf'](lastInstance);
      type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
      var fn = type ? type[[key.substring(1)]] : _undefined;
      if (fn) {
        instance = bind(lastInstance, fn, lastInstance);
        return instance;
      }
    }
  }
  if (!unboundFn && isFunction(instance)) {
    return bind(lastInstance, instance);
  }
  return instance;
}

function setter(instance, path, value){
  var element = path.split('.');
  for ( var i = 0; element.length > 1; i++) {
    var key = element.shift();
    var newInstance = instance[key];
    if (!newInstance) {
      newInstance = {};
      instance[key] = newInstance;
    }
    instance = newInstance;
  }
  instance[element.shift()] = value;
  return value;
}

///////////////////////////////////
var scopeId = 0,
    getterFnCache = {},
    compileCache = {},
    JS_KEYWORDS = {};
foreach(
    ("abstract,boolean,break,byte,case,catch,char,class,const,continue,debugger,default," +
    "delete,do,double,else,enum,export,extends,false,final,finally,float,for,function,goto," +
    "if,implements,import,ininstanceof,intinterface,long,native,new,null,package,private," +
    "protected,public,return,short,static,super,switch,synchronized,this,throw,throws," +
    "transient,true,try,typeof,var,volatile,void,undefined,while,with").split(/,/),
  function(key){ JS_KEYWORDS[key] = true;}
);
function getterFn(path){
  var fn = getterFnCache[path];
  if (fn) return fn;

  var code = 'var l, fn, t;\n';
  foreach(path.split('.'), function(key) {
    key = (JS_KEYWORDS[key]) ? '["' + key + '"]' : '.' + key;
    code += 'if(!s) return s;\n' +
            'l=s;\n' +
            's=s' + key + ';\n' +
            'if(typeof s=="function") s = function(){ return l'+key+'.apply(l, arguments); };\n';
    if (key.charAt(1) == '$') {
      // special code for super-imposed functions
      var name = key.substr(2);
      code += 'if(!s) {\n' +
              '  t = angular.Global.typeOf(l);\n' +
              '  fn = (angular[t.charAt(0).toUpperCase() + t.substring(1)]||{})["' + name + '"];\n' +
              '  if (fn) s = function(){ return fn.apply(l, [l].concat(Array.prototype.slice.call(arguments, 0, arguments.length))); };\n' +
              '}\n';
    }
  });
  code += 'return s;';
  fn = Function('s', code);
  fn["toString"] = function(){ return code; };

  return getterFnCache[path] = fn;
}

///////////////////////////////////

function expressionCompile(exp){
  if (typeof exp === $function) return exp;
  var fn = compileCache[exp];
  if (!fn) {
    var p = parser(exp);
    var fnSelf = p.statements();
    p.assertAllConsumed();
    fn = compileCache[exp] = extend(
      function(){ return fnSelf(this);},
      {fnSelf: fnSelf});
  }
  return fn;
}

function errorHandlerFor(element, error) {
  elementError(element, NG_EXCEPTION, isDefined(error) ? formatError(error) : error);
}

/**
 * @ngdoc overview
 * @name angular.scope
 *
 * @description
 * Scope is a JavaScript object and the execution context for expressions. You can think about
 * scopes as JavaScript objects that have extra APIs for registering watchers. A scope is the model
 * in the model-view-controller design pattern.
 *
 * A few other characteristics of scopes:
 *
 * - Scopes can be nested. A scope (prototypically) inherits properties from its parent scope.
 * - Scopes can be attached (bound) to the HTML DOM tree (the view).
 * - A scope {@link angular.scope.$become becomes} `this` for a controller.
 * - Scope's {@link angular.scope.$eval $eval} is used to update its view.
 * - Scopes can {@link angular.scope.$watch watch} properties and fire events.
 *
 * # Basic Operations
 * Scopes can be created by calling {@link angular.scope() angular.scope()} or by compiling HTML.
 *
 * {@link angular.widget Widgets} and data bindings register listeners on the current scope to get
 * notified of changes to the scope state. When notified, these listeners push the updated state
 * through to the DOM.
 *
 * Here is a simple scope snippet to show how you can interact with the scope.
 *

       var scope = angular.scope();
       scope.salutation = 'Hello';
       scope.name = 'World';

       expect(scope.greeting).toEqual(undefined);

       scope.$watch('name', function(){
         this.greeting = this.salutation + ' ' + this.name + '!';
       });

       expect(scope.greeting).toEqual('Hello World!');
       scope.name = 'Misko';
       // scope.$eval() will propagate the change to listeners
       expect(scope.greeting).toEqual('Hello World!');

       scope.$eval();
       expect(scope.greeting).toEqual('Hello Misko!');
 *

 *
 * # Inheritance
 * A scope can inherit from a parent scope, as in this example:
 *

     var parent = angular.scope();
     var child = angular.scope(parent);

     parent.salutation = "Hello";
     child.name = "World";
     expect(child.salutation).toEqual('Hello');

     child.salutation = "Welcome";
     expect(child.salutation).toEqual('Welcome');
     expect(parent.salutation).toEqual('Hello');
 *

 *
 * # Dependency Injection
 * Scope also acts as a simple dependency injection framework.
 *
 * **TODO**: more info needed
 *
 * # When scopes are evaluated
 * Anyone can update a scope by calling its {@link angular.scope.$eval $eval()} method. By default
 * angular widgets listen to user change events (e.g. the user enters text into text field), copy
 * the data from the widget to the scope (the MVC model), and then call the `$eval()` method on the
 * root scope to update dependents. This creates a spreadsheet-like behavior: the bound views update
 * immediately as the user types into the text field.
 *
 * Similarly, when a request to fetch data from a server is made and the response comes back, the
 * data is written into the model and then $eval() is called to push updates through to the view and
 * any other dependents.
 *
 * Because a change in the model that's triggered either by user input or by server response calls
 * `$eval()`, it is unnecessary to call `$eval()` from within your controller. The only time when
 * calling `$eval()` is needed, is when implementing a custom widget or service.
 *
 * Because scopes are inherited, the child scope `$eval()` overrides the parent `$eval()` method.
 * So to update the whole page you need to call `$eval()` on the root scope as `$root.$eval()`.
 *
 * Note: A widget that creates scopes (i.e. {@link angular.widget.@ng:repeat ng:repeat}) is
 * responsible for forwarding `$eval()` calls from the parent to those child scopes. That way,
 * calling $eval() on the root scope will update the whole page.

 *
 * @exampleDescription
 * This example demonstrates scope inheritance and property overriding.
 *
 * In this example, the root scope encompasses the whole HTML DOM tree. This scope has `salutation`,
 * `name`, and `names` properties. The {@link angular.widget@ng:repeat ng:repeat} creates a child
 * scope, one for each element in the names array. The repeater also assigns $index and name into
 * the child scope.
 *
 * Notice that:
 *
 * - While the name is set in the child scope it does not change the name defined in the root scope.
 * - The child scope inherits the salutation property from the root scope.
 * - The $index property does not leak from the child scope to the root scope.
 *
 * @example

       {{$index}}: {{salutation}} {{name}}!

   $index={{$index}}
   salutation={{salutation}}
   name={{name}}

   @scenario
   it('should inherit the salutation property and override the name property', function() {
     expect(using('.doc-example-live').repeater('li').row(0)).
       toEqual(['0', 'Hello', 'World']);
     expect(using('.doc-example-live').repeater('li').row(1)).
       toEqual(['1', 'Hello', 'Earth']);
     expect(using('.doc-example-live').element('pre').text()).
       toBe('$index=\nsalutation=Hello\nname=Misko');
   });

 */
function createScope(parent, providers, instanceCache) {
  function Parent(){}
  parent = Parent.prototype = (parent || {});
  var instance = new Parent();
  var evalLists = {sorted:[]};
  var postList = [], postHash = {}, postId = 0;

  extend(instance, {
    'this': instance,
    $id: (scopeId++),
    $parent: parent,

    /**
     * @ngdoc function
     * @name angular.scope.$bind
     * @function
     *
     * @description
     * Binds a function `fn` to the current scope. See: {@link angular.bind}.

         var scope = angular.scope();
         var fn = scope.$bind(function(){
           return this;
         });
         expect(fn()).toEqual(scope);

     *
     * @param {function} fn Function to be bound.
     */
    $bind: bind(instance, bind, instance),
    $get: bind(instance, getter, instance),
    $set: bind(instance, setter, instance),

    /**
     * @ngdoc function
     * @name angular.scope.$eval
     * @function
     *
     * @description
     * Without the `exp` parameter triggers an eval cycle, for this scope and it's child scopes.
     *
     * With the `exp` parameter, compiles the expression to a function and calls it with `this` set
     * to the current scope and returns the result.
     *
     * # Example

         var scope = angular.scope();
         scope.a = 1;
         scope.b = 2;

         expect(scope.$eval('a+b')).toEqual(3);
         expect(scope.$eval(function(){ return this.a + this.b; })).toEqual(3);

         scope.$onEval('sum = a+b');
         expect(scope.sum).toEqual(undefined);
         scope.$eval();
         expect(scope.sum).toEqual(3);

     *
     * @param {(string|function)=} exp An angular expression to be compiled to a function or a js
     *     function.
     *
     * @returns {*} The result of calling compiled `exp` with `this` set to the current scope.
     */
    $eval: function(exp) {
      var type = typeof exp;
      var i, iSize;
      var j, jSize;
      var queue;
      var fn;
      if (type == $undefined) {
        for ( i = 0, iSize = evalLists.sorted.length; i < iSize; i++) {
          for ( queue = evalLists.sorted[i],
              jSize = queue.length,
              j= 0; j < jSize; j++) {
            instance.$tryEval(queue[j].fn, queue[j].handler);
          }
        }
        while(postList.length) {
          fn = postList.shift();
          delete postHash[fn.$postEvalId];
          instance.$tryEval(fn);
        }
      } else if (type === $function) {
        return exp.call(instance);
      } else  if (type === 'string') {
        return expressionCompile(exp).call(instance);
      }
    },

    /**
     * @ngdoc function
     * @name angular.scope.$tryEval
     * @function
     *
     * @description
     * Evaluates the expression in the context of the current scope just like
     * {@link angular.scope.$eval()} with expression parameter, but also wraps it in a try/catch
     * block.
     *
     * If exception is thrown then `exceptionHandler` is used to handle the exception.
     *
     * # Example

         var scope = angular.scope();
         scope.error = function(){ throw 'myerror'; };
         scope.$exceptionHandler = function(e) {this.lastException = e; };

         expect(scope.$eval('error()'));
         expect(scope.lastException).toEqual('myerror');
         this.lastException = null;

         expect(scope.$eval('error()'),  function(e) {this.lastException = e; });
         expect(scope.lastException).toEqual('myerror');

         var body = angular.element(window.document.body);
         expect(scope.$eval('error()'), body);
         expect(body.attr('ng-exception')).toEqual('"myerror"');
         expect(body.hasClass('ng-exception')).toEqual(true);

     *
     * @param {string|function} expression Angular expression to evaluate.
     * @param {function|DOMElement} exceptionHandler Function to be called or DOMElement to be
     *     decorated.
     * @returns {*} The result of `expression` evaluation.
     */
    $tryEval: function (expression, exceptionHandler) {
      var type = typeof expression;
      try {
        if (type == $function) {
          return expression.call(instance);
        } else if (type == 'string'){
          return expressionCompile(expression).call(instance);
        }
      } catch (e) {
        (instance.$log || {error:error}).error(e);
        if (isFunction(exceptionHandler)) {
          exceptionHandler(e);
        } else if (exceptionHandler) {
          errorHandlerFor(exceptionHandler, e);
        } else if (isFunction(instance.$exceptionHandler)) {
          instance.$exceptionHandler(e);
        }
      }
    },

    /**
     * @ngdoc function
     * @name angular.scope.$watch
     * @function
     *
     * @description
     * Registers `listener` as a callback to be executed every time the `watchExp` changes. Be aware
     * that callback gets, by default, called upon registration, this can be prevented via the
     * `initRun` parameter.
     *
     * # Example

         var scope = angular.scope();
         scope.name = 'misko';
         scope.counter = 0;

         expect(scope.counter).toEqual(0);
         scope.$watch('name', 'counter = counter + 1');
         expect(scope.counter).toEqual(1);

         scope.$eval();
         expect(scope.counter).toEqual(1);

         scope.name = 'adam';
         scope.$eval();
         expect(scope.counter).toEqual(2);

     *
     * @param {function|string} watchExp Expression that should be evaluated and checked for change
     *    during each eval cycle. Can be an angular string expression or a function.
     * @param {function|string} listener Function (or angular string expression) that gets called
     *    every time the value of the `watchExp` changes. The function will be called with two
     *    parameters, `newValue` and `oldValue`.
     * @param {(function|DOMElement)=} [exceptionHanlder=angular.service.$exceptionHandler] Handler
     *    that gets called when `watchExp` or `listener` throws an exception. If a DOMElement is
     *    specified as handler, the element gets decorated by angular with the information about the
     *    exception.
     * @param {boolean=} [initRun=true] Flag that prevents the first execution of the listener upon
     *    registration.
     *
     */
    $watch: function(watchExp, listener, exceptionHandler, initRun) {
      var watch = expressionCompile(watchExp),
          last = watch.call(instance);
      listener = expressionCompile(listener);
      function watcher(firstRun){
        var value = watch.call(instance),
            // we have to save the value because listener can call ourselves => inf loop
            lastValue = last;
        if (firstRun || lastValue !== value) {
          last = value;
          instance.$tryEval(function(){
            return listener.call(instance, value, lastValue);
          }, exceptionHandler);
        }
      }
      instance.$onEval(PRIORITY_WATCH, watcher);
      if (isUndefined(initRun)) initRun = true;
      if (initRun) watcher(true);
    },

    /**
     * @ngdoc function
     * @name angular.scope.$onEval
     * @function
     *
     * @description
     * Evaluates the `expr` expression in the context of the current scope during each
     * {@link angular.scope.$eval eval cycle}.
     *
     * # Example

         var scope = angular.scope();
         scope.counter = 0;
         scope.$onEval('counter = counter + 1');
         expect(scope.counter).toEqual(0);
         scope.$eval();
         expect(scope.counter).toEqual(1);

     *
     * @param {number} [priority=0] Execution priority. Lower priority numbers get executed first.
     * @param {string|function} expr Angular expression or function to be executed.
     * @param {(function|DOMElement)=} [exceptionHandler=angular.service.$exceptionHandler] Handler
     *     function to call or DOM element to decorate when an exception occurs.
     *
     */
    $onEval: function(priority, expr, exceptionHandler){
      if (!isNumber(priority)) {
        exceptionHandler = expr;
        expr = priority;
        priority = 0;
      }
      var evalList = evalLists[priority];
      if (!evalList) {
        evalList = evalLists[priority] = [];
        evalList.priority = priority;
        evalLists.sorted.push(evalList);
        evalLists.sorted.sort(function(a,b){return a.priority-b.priority;});
      }
      evalList.push({
        fn: expressionCompile(expr),
        handler: exceptionHandler
      });
    },

    /**
     * @ngdoc function
     * @name angular.scope.$postEval
     * @function
     */
    $postEval: function(expr) {
      if (expr) {
        var fn = expressionCompile(expr);
        var id = fn.$postEvalId;
        if (!id) {
          id = '$' + instance.$id + "_" + (postId++);
          fn.$postEvalId = id;
        }
        if (!postHash[id]) {
          postList.push(postHash[id] = fn);
        }
      }
    },

    /**
     * @ngdoc function
     * @name angular.scope.$become
     * @function
     * @deprecated This method will be removed before 1.0
     *
     * @description
     * Modifies the scope to act like an instance of the given class by:
     *
     * - copying the class's prototype methods
     * - applying the class's initialization function to the scope instance (without using the new
     *   operator)
     *
     * That makes the scope be a `this` for the given class's methods — effectively an instance of
     * the given class with additional (scope) stuff. A scope can later `$become` another class.
     *
     * `$become` gets used to make the current scope act like an instance of a controller class.
     * This allows for use of a controller class in two ways.
     *
     * - as an ordinary JavaScript class for standalone testing, instantiated using the new
     *   operator, with no attached view.
     * - as a controller for an angular model stored in a scope, "instantiated" by
     *   `scope.$become(ControllerClass)`.
     *
     * Either way, the controller's methods refer to the model  variables like `this.name`. When
     * stored in a scope, the model supports data binding. When bound to a view, {{name}} in the
     * HTML template refers to the same variable.
     */
    $become: function(Class) {
      if (isFunction(Class)) {
        instance.constructor = Class;
        foreach(Class.prototype, function(fn, name){
          instance[name] = bind(instance, fn);
        });
        instance.$inject.apply(instance, concat([Class, instance], arguments, 1));

        //TODO: backwards compatibility hack, remove when we don't depend on init methods
        if (isFunction(Class.prototype.init)) {
          instance.init();
        }
      }
    },

    /**
     * @ngdoc function
     * @name angular.scope.$new
     * @function
     *
     * @description
     * Creates a new {@link angular.scope scope}, that:
     *
     * - is a child of the current scope
     * - will {@link angular.scope.$become $become} of type specified via `constructor`
     *
     * @param {function} constructor Constructor function of the type the new scope should assume.
     * @returns {Object} The newly created child scope.
     *
     */
    $new: function(constructor) {
      var child = createScope(instance);
      child.$become.apply(instance, concat([constructor], arguments, 1));
      instance.$onEval(child.$eval);
      return child;
    }

  });

  if (!parent.$root) {
    instance.$root = instance;
    instance.$parent = instance;
    (instance.$inject = createInjector(instance, providers, instanceCache))();
  }

  return instance;
}
<|endoftext|>


<commit_before>'use strict';

/**
* @namespace wildstring
* @property {string} wildcard the wildcard to use in your strings, defaults to '*'
* @property {boolean} caseSensitive whether matches should care about case, defaults to true
*/
var wildstring = {
	wildcard: '*',
	caseSensitive: true,

	/**
	* When a match doesn't continue to the end of the string, this function rolls back to try again with the rest of the string
	* @memberof wildstring
	* @access private
	* @param {string[]} rollbackStrings The list of substrings that appeared prior to the current match
	* @param {string[]} patternSubstrings The matching list of pattens that need to be matched before the current pattern
	*/
	checkRollbackStrings: function (rollbackStrings, patternSubstrings) {
		for (var s = 0; s < rollbackStrings.length; ++s) {
			var currentString = rollbackStrings[s].string;	// starting with the rolled back string
			var patternIndex = rollbackStrings[s].index;

			while (patternIndex < patternSubstrings.length) {
				if (currentString.indexOf(patternSubstrings[patternIndex]) === -1) {
					break;
				}

				var testString = currentString.substr(1);	//remove just one char to retest
				rollbackStrings.push({ string: testString, index: patternIndex });
				if (testString.indexOf(patternSubstrings[patternIndex]) === -1) {
					rollbackStrings.pop();
					break;
				}

				currentString = currentString.substr(
					currentString.indexOf(patternSubstrings[patternIndex]) + patternSubstrings[patternIndex].length
				);

				patternIndex++;
				while (patternSubstrings[patternIndex] === '') {
					patternIndex++;
				}

				if (patternIndex >= patternSubstrings.length) {
					if (patternSubstrings[patternSubstrings.length - 1] !== '' &&
						currentString.length > 0) {
						// not ending with a wildcard, we need to backtrack
						break;
					}
					else {
						return true;
					}
				}
			}
		}

		return false;
	},

	/**
	* Check if a string matches a pattern
	* @memberof wildstring
	* @param {string} pattern The pattern to match using the configured wildcard
	* @param {string} string The string to test for a match
	*/
	match: function (pattern, string) {
		// if there are no wildcards, must be exact
		if (pattern.indexOf(wildstring.wildcard) === -1) {
			return pattern === string;
		}
		if (!wildstring.caseSensitive) {
			pattern = pattern.toLowerCase();
			string = string.toLowerCase();
		}
		var patternSubstrings = pattern.split(wildstring.wildcard);

		var patternIndex = 0;
		var currentString = string;

		// find pattern beginning
		while (patternSubstrings[patternIndex] === '') {
			patternIndex++;
			// if the pattern is just wildcards, it matches
			if (patternIndex === pattern.length) {
				return true;
			}
		}

		if (patternIndex === 0 && string.indexOf(patternSubstrings[0]) !== 0) {
			// not starting with a wildcard
			return false;
		}

		var rollbackStrings = [];

		while (patternIndex < patternSubstrings.length) {
			if (currentString.indexOf(patternSubstrings[patternIndex]) === -1) {
				return wildstring.checkRollbackStrings(rollbackStrings, patternSubstrings);
			}

			// create a queue of strings to roll back and try again if we fail later
			var testString = currentString.substr(1);	//remove just one char to retest
			rollbackStrings.push({ string: testString, index: patternIndex });
			if (testString.indexOf(patternSubstrings[patternIndex]) === -1) {
				rollbackStrings.pop();
			}

			currentString = currentString.substr(
				currentString.indexOf(patternSubstrings[patternIndex]) + patternSubstrings[patternIndex].length
			);

			patternIndex++;
			while (patternSubstrings[patternIndex] === '') {
				patternIndex++;
			}
		}

		if (patternIndex >= patternSubstrings.length &&
				patternSubstrings[patternSubstrings.length - 1] !== '' &&
				currentString.length > 0) {
			// not ending with a wildcard, we need to backtrack
			if (currentString === string) { // this string doesn't even match a little
				return false;
			}

			return wildstring.checkRollbackStrings(rollbackStrings, patternSubstrings);
		}

		return true;
	},

	/**
	* Replace wildcards in a pattern with strings (string interpolation)
	* @memberof wildstring
	* @param {string} pattern The start string, using wildcards as placeholders
	* @param {string|string[]} strings The string or strings to replace the wildcards in the pattern.
	* 	If you pass a single string, it will replace all the wildcards with the string.
	* 	If you pass an array of strings, they will replace the wildcards in order from left to right.
	* @throws The number of items in the strings array (if you pass an array) must match the number of wildcards in the pattern string.
	* @throws You need to pass both parameters
	* @throws You need to pass the right types
	*/
	replace: function (pattern, strings) {
		if (pattern === undefined || strings === undefined) {
			throw new Error('wildstring.replace takes the pattern as one parameter and either a string or an array of strings as the second.  You didn\'t pass enough parameters.');
		}
		if (typeof(strings) === typeof('')) {
			return pattern.replace(wildstring.wildcard, strings);
		}
		if (!Array.isArray(strings) || typeof(pattern) !== typeof('')) {
			throw new Error('wildstring.replace takes the pattern as one parameter and either a string or an array of strings as the second.  Your parameter types are incorrect.');
		}
		if (pattern.indexOf(wildstring.wildcard) === -1) {
			return pattern; // if there are no wildcards, just return the pattern
		}
		var patternSubstrings = pattern.split(wildstring.wildcard);
		if (patternSubstrings.length - 1 !== strings.length) {
			var message = 'There are a different number of wildcards than strings to replace them. You have ' +
				wildstring.wildcard +' wildcards in "' + wildstring.wildcard + '" and ' + wildstring.wildcard +
				' replacement strings.';
			throw new Error(wildstring.replace(message, [ patternSubstrings.length - 1, pattern, strings.length ]));
		}

		var result = '';

		for (var s = 0; s < strings.length; ++s) {
			result += patternSubstrings[s] + strings[s];
		}

		return result;
	}
};

if (typeof(module) !== 'undefined') { module.exports = wildstring; }
if (typeof(angular) !== 'undefined') { angular.module('wildstring').factory = wildstring; }
if (typeof(define) !== 'undefined') { define([], wildstring); }
<commit_msg>bugfix: create angular module correctly<commit_after>'use strict';

/**
* @namespace wildstring
* @property {string} wildcard the wildcard to use in your strings, defaults to '*'
* @property {boolean} caseSensitive whether matches should care about case, defaults to true
*/
var wildstring = {
	wildcard: '*',
	caseSensitive: true,

	/**
	* When a match doesn't continue to the end of the string, this function rolls back to try again with the rest of the string
	* @memberof wildstring
	* @access private
	* @param {string[]} rollbackStrings The list of substrings that appeared prior to the current match
	* @param {string[]} patternSubstrings The matching list of pattens that need to be matched before the current pattern
	*/
	checkRollbackStrings: function (rollbackStrings, patternSubstrings) {
		for (var s = 0; s < rollbackStrings.length; ++s) {
			var currentString = rollbackStrings[s].string;	// starting with the rolled back string
			var patternIndex = rollbackStrings[s].index;

			while (patternIndex < patternSubstrings.length) {
				if (currentString.indexOf(patternSubstrings[patternIndex]) === -1) {
					break;
				}

				var testString = currentString.substr(1);	//remove just one char to retest
				rollbackStrings.push({ string: testString, index: patternIndex });
				if (testString.indexOf(patternSubstrings[patternIndex]) === -1) {
					rollbackStrings.pop();
					break;
				}

				currentString = currentString.substr(
					currentString.indexOf(patternSubstrings[patternIndex]) + patternSubstrings[patternIndex].length
				);

				patternIndex++;
				while (patternSubstrings[patternIndex] === '') {
					patternIndex++;
				}

				if (patternIndex >= patternSubstrings.length) {
					if (patternSubstrings[patternSubstrings.length - 1] !== '' &&
						currentString.length > 0) {
						// not ending with a wildcard, we need to backtrack
						break;
					}
					else {
						return true;
					}
				}
			}
		}

		return false;
	},

	/**
	* Check if a string matches a pattern
	* @memberof wildstring
	* @param {string} pattern The pattern to match using the configured wildcard
	* @param {string} string The string to test for a match
	*/
	match: function (pattern, string) {
		// if there are no wildcards, must be exact
		if (pattern.indexOf(wildstring.wildcard) === -1) {
			return pattern === string;
		}
		if (!wildstring.caseSensitive) {
			pattern = pattern.toLowerCase();
			string = string.toLowerCase();
		}
		var patternSubstrings = pattern.split(wildstring.wildcard);

		var patternIndex = 0;
		var currentString = string;

		// find pattern beginning
		while (patternSubstrings[patternIndex] === '') {
			patternIndex++;
			// if the pattern is just wildcards, it matches
			if (patternIndex === pattern.length) {
				return true;
			}
		}

		if (patternIndex === 0 && string.indexOf(patternSubstrings[0]) !== 0) {
			// not starting with a wildcard
			return false;
		}

		var rollbackStrings = [];

		while (patternIndex < patternSubstrings.length) {
			if (currentString.indexOf(patternSubstrings[patternIndex]) === -1) {
				return wildstring.checkRollbackStrings(rollbackStrings, patternSubstrings);
			}

			// create a queue of strings to roll back and try again if we fail later
			var testString = currentString.substr(1);	//remove just one char to retest
			rollbackStrings.push({ string: testString, index: patternIndex });
			if (testString.indexOf(patternSubstrings[patternIndex]) === -1) {
				rollbackStrings.pop();
			}

			currentString = currentString.substr(
				currentString.indexOf(patternSubstrings[patternIndex]) + patternSubstrings[patternIndex].length
			);

			patternIndex++;
			while (patternSubstrings[patternIndex] === '') {
				patternIndex++;
			}
		}

		if (patternIndex >= patternSubstrings.length &&
				patternSubstrings[patternSubstrings.length - 1] !== '' &&
				currentString.length > 0) {
			// not ending with a wildcard, we need to backtrack
			if (currentString === string) { // this string doesn't even match a little
				return false;
			}

			return wildstring.checkRollbackStrings(rollbackStrings, patternSubstrings);
		}

		return true;
	},

	/**
	* Replace wildcards in a pattern with strings (string interpolation)
	* @memberof wildstring
	* @param {string} pattern The start string, using wildcards as placeholders
	* @param {string|string[]} strings The string or strings to replace the wildcards in the pattern.
	* 	If you pass a single string, it will replace all the wildcards with the string.
	* 	If you pass an array of strings, they will replace the wildcards in order from left to right.
	* @throws The number of items in the strings array (if you pass an array) must match the number of wildcards in the pattern string.
	* @throws You need to pass both parameters
	* @throws You need to pass the right types
	*/
	replace: function (pattern, strings) {
		if (pattern === undefined || strings === undefined) {
			throw new Error('wildstring.replace takes the pattern as one parameter and either a string or an array of strings as the second.  You didn\'t pass enough parameters.');
		}
		if (typeof(strings) === typeof('')) {
			return pattern.replace(wildstring.wildcard, strings);
		}
		if (!Array.isArray(strings) || typeof(pattern) !== typeof('')) {
			throw new Error('wildstring.replace takes the pattern as one parameter and either a string or an array of strings as the second.  Your parameter types are incorrect.');
		}
		if (pattern.indexOf(wildstring.wildcard) === -1) {
			return pattern; // if there are no wildcards, just return the pattern
		}
		var patternSubstrings = pattern.split(wildstring.wildcard);
		if (patternSubstrings.length - 1 !== strings.length) {
			var message = 'There are a different number of wildcards than strings to replace them. You have ' +
				wildstring.wildcard +' wildcards in "' + wildstring.wildcard + '" and ' + wildstring.wildcard +
				' replacement strings.';
			throw new Error(wildstring.replace(message, [ patternSubstrings.length - 1, pattern, strings.length ]));
		}

		var result = '';

		for (var s = 0; s < strings.length; ++s) {
			result += patternSubstrings[s] + strings[s];
		}

		return result;
	}
};

if (typeof(module) !== 'undefined') { module.exports = wildstring; }
if (typeof(angular) !== 'undefined') { angular.module('wildstring', []).factory = wildstring; }
if (typeof(define) !== 'undefined') { define([], wildstring); }
<|endoftext|>


<commit_before>/**
  @module ember-flexberry-gis
*/

import Ember from 'ember';
import BaseLayer from '../base-layer';

/**
  WFS layer component for leaflet map.

  @class WfsLayerComponent
  @extend BaseLayerComponent
 */
export default BaseLayer.extend({
  leafletOptions: [
    'pointToLayer', 'style', 'onEachFeature', 'filter', 'coordsToLatLng', 'geojson'
  ],

  layerFunctions: ['pointToLayer', 'style', 'onEachFeature', 'filter', 'coordsToLatLng'],

  /**
    Sets leaflet layer's visibility.

    @method _setLayerOpacity
    @private
  */
  _setLayerOpacity() {
    let leafletLayer = this.get('_leafletObject');
    let leafletLayerStyle = Ember.get(leafletLayer, 'options.style');
    if (Ember.isNone(leafletLayerStyle)) {
      leafletLayerStyle = {};
      Ember.set(leafletLayer, 'options.style', leafletLayerStyle);
    }

    let opacity = this.get('opacity');
    Ember.set(leafletLayerStyle, 'opacity', opacity);
    Ember.set(leafletLayerStyle, 'fillOpacity', opacity);

    leafletLayer.setStyle(leafletLayerStyle);
  },

  /**
    Creates leaflet layer related to layer type.

    @method createLayer
    @returns L.Layer|Ember.RSVP.Promise
    Leaflet layer or promise returning such layer.
  */
  createLayer(options) {
    options = Ember.$.extend(true, {}, this.get('options'), options);
    let geojson = options.geojson || {};
    options = options || {};

    let featureCollection = {
      type: 'FeatureCollection',
      features: []
    };

    if (Ember.isArray(geojson)) {
      Ember.set(featureCollection, 'features', geojson);
    } else if (Ember.get(geojson, 'type') === 'Feature') {
      Ember.set(featureCollection, 'features', [geojson]);
    } else if (Ember.get(geojson, 'type') === 'FeatureCollection') {
      featureCollection = geojson;
    }

    let features = Ember.A(Ember.get(featureCollection, 'features') || []);
    if (Ember.get(features, 'length') === 0) {
      return L.geoJSON();
    }

    let layerFunctions = this.get('layerFunctions');
    let customFunction;
    for (let i = 0; i < layerFunctions.length; i++) {
      customFunction = Ember.get(options, layerFunctions[i]);
      if (customFunction) {
        Ember.set(options, layerFunctions[i], new Function('return ' + customFunction)());
      }
    }

    return L.geoJSON(featureCollection, options);
  },

  /**
    Handles 'flexberry-map:identify' event of leaflet map.

    @method identify
    @param {Object} e Event object.
    @param {L.Polygon} polygonLayer Polygon layer related to given area.
    @param {Object[]} layers Objects describing those layers which must be identified.
    @param {Object[]} results Objects describing identification results.
    Every result-object has the following structure: { layer: ..., features: [...] },
    where 'layer' is metadata of layer related to identification result, features is array
    containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  identify(e) {
    var bounds = new Terraformer.Primitive(e.polygonLayer.toGeoJSON());

    let geojsonLayer = this.get('_leafletObject');

    //console.log("grouplayer: "+ groupLayer);
    return new Ember.RSVP.Promise((resolve, reject) => {
      let features = Ember.A();
      geojsonLayer.eachLayer(function(layer) {
        let geoLayer = layer.toGeoJSON();
        let primitive = new Terraformer.Primitive(geoLayer.geometry);

        if (primitive instanceof Terraformer.Point ? primitive.within(bounds) : (primitive.intersects(bounds) || primitive.within(bounds))) {
          features.pushObject(geoLayer);
        }
      });
      resolve(features);
    });
  },

  /**
    Handles 'flexberry-map:search' event of leaflet map.

    @method search
    @param {Object} e Event object.
    @param {L.LatLng} e.latlng Center of the search area.
    @param {Object[]} layer Object describing layer that must be searched.
    @param {Object} searchOptions Search options related to layer type.
    @param {Object} results Hash containing search results.
    @param {Object[]} results.features Array containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  search(e) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      let geojLayer = this.get('_leafletObject');
      let features = Ember.A();
       geojLayer.eachLayer((layer) => {
        if (features.length < e.searchOptions.maxResultsCount) {
          let feature = Ember.get(layer, 'feature');
          let geoLayer = layer.toGeoJSON();

          // if layer satisfies search query
          let searchFields = this.get('searchSettings.searchFields'); // []
          let contains = searchFields.map((item) => {
            return feature.properties[item].toLowerCase().includes(e.searchOptions.queryString.toLowerCase());
          }).reduce((result, current) => {
            return result || current; // if any field contains
          }, false);

          if (contains) {
            features.pushObject(geoLayer);
            }
          }
        });
      resolve(features);
    });
  },

  /**
    Handles 'flexberry-map:query' event of leaflet map.

    @method _query
    @param {Object} e Event object.
    @param {Object} queryFilter Object with query filter paramteres
    @param {Object[]} results.features Array containing leaflet layers objects
    or a promise returning such array.
  */
  query(e) {

  }
});
<commit_msg>Update geojson-layer.js<commit_after>/**
  @module ember-flexberry-gis
*/

import Ember from 'ember';
import BaseLayer from '../base-layer';

/**
  WFS layer component for leaflet map.

  @class WfsLayerComponent
  @extend BaseLayerComponent
 */
export default BaseLayer.extend({
  leafletOptions: [
    'pointToLayer', 'style', 'onEachFeature', 'filter', 'coordsToLatLng', 'geojson'
  ],

  layerFunctions: ['pointToLayer', 'style', 'onEachFeature', 'filter', 'coordsToLatLng'],

  /**
    Sets leaflet layer's visibility.

    @method _setLayerOpacity
    @private
  */
  _setLayerOpacity() {
    let leafletLayer = this.get('_leafletObject');
    let leafletLayerStyle = Ember.get(leafletLayer, 'options.style');
    if (Ember.isNone(leafletLayerStyle)) {
      leafletLayerStyle = {};
      Ember.set(leafletLayer, 'options.style', leafletLayerStyle);
    }

    let opacity = this.get('opacity');
    Ember.set(leafletLayerStyle, 'opacity', opacity);
    Ember.set(leafletLayerStyle, 'fillOpacity', opacity);

    leafletLayer.setStyle(leafletLayerStyle);
  },

  /**
    Creates leaflet layer related to layer type.

    @method createLayer
    @returns L.Layer|Ember.RSVP.Promise
    Leaflet layer or promise returning such layer.
  */
  createLayer(options) {
    options = Ember.$.extend(true, {}, this.get('options'), options);
    let geojson = options.geojson || {};
    options = options || {};

    let featureCollection = {
      type: 'FeatureCollection',
      features: []
    };

    if (Ember.isArray(geojson)) {
      Ember.set(featureCollection, 'features', geojson);
    } else if (Ember.get(geojson, 'type') === 'Feature') {
      Ember.set(featureCollection, 'features', [geojson]);
    } else if (Ember.get(geojson, 'type') === 'FeatureCollection') {
      featureCollection = geojson;
    }

    let features = Ember.A(Ember.get(featureCollection, 'features') || []);
    if (Ember.get(features, 'length') === 0) {
      return L.geoJSON();
    }

    let layerFunctions = this.get('layerFunctions');
    let customFunction;
    for (let i = 0; i < layerFunctions.length; i++) {
      customFunction = Ember.get(options, layerFunctions[i]);
      if (customFunction) {
        Ember.set(options, layerFunctions[i], new Function('return ' + customFunction)());
      }
    }

    return L.geoJSON(featureCollection, options);
  },

  /**
    Handles 'flexberry-map:identify' event of leaflet map.

    @method identify
    @param {Object} e Event object.
    @param {L.Polygon} polygonLayer Polygon layer related to given area.
    @param {Object[]} layers Objects describing those layers which must be identified.
    @param {Object[]} results Objects describing identification results.
    Every result-object has the following structure: { layer: ..., features: [...] },
    where 'layer' is metadata of layer related to identification result, features is array
    containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  identify(e) {
    var bounds = new Terraformer.Primitive(e.polygonLayer.toGeoJSON());

    let geojsonLayer = this.get('_leafletObject');

    //console.log("grouplayer: "+ groupLayer);
    return new Ember.RSVP.Promise((resolve, reject) => {
      let features = Ember.A();
      geojsonLayer.eachLayer(function(layer) {
        let geoLayer = layer.toGeoJSON();
        let primitive = new Terraformer.Primitive(geoLayer.geometry);

        if (primitive instanceof Terraformer.Point ? primitive.within(bounds) : (primitive.intersects(bounds) || primitive.within(bounds))) {
          features.pushObject(geoLayer);
        }
      });
      resolve(features);
    });
  },

  /**
    Handles 'flexberry-map:search' event of leaflet map.

    @method search
    @param {Object} e Event object.
    @param {L.LatLng} e.latlng Center of the search area.
    @param {Object[]} layer Object describing layer that must be searched.
    @param {Object} searchOptions Search options related to layer type.
    @param {Object} results Hash containing search results.
    @param {Object[]} results.features Array containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  search(e) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      let geojLayer = this.get('_leafletObject');
      let features = Ember.A();
      geojLayer.eachLayer((layer) => {
        if (features.length < e.searchOptions.maxResultsCount) {
          let feature = Ember.get(layer, 'feature');
          let geoLayer = layer.toGeoJSON();

          // if layer satisfies search query
          let searchFields = this.get('searchSettings.searchFields'); // []
          let contains = searchFields.map((item) => {
            return feature.properties[item].toLowerCase().includes(e.searchOptions.queryString.toLowerCase());
          }).reduce((result, current) => {
            return result || current; // if any field contains
          }, false);

          if (contains) {
            features.pushObject(geoLayer);
          }
        }
      });
      resolve(features);
    });
  },

  /**
    Handles 'flexberry-map:query' event of leaflet map.

    @method _query
    @param {Object} e Event object.
    @param {Object} queryFilter Object with query filter paramteres
    @param {Object[]} results.features Array containing leaflet layers objects
    or a promise returning such array.
  */
  query(e) {

  }
});
<|endoftext|>