<commit_before>/**
 * The purpose of the ActivityMapLayerView is render feature collection GeoJson on the map.
 */
define([
    'underscore',
    'backbone',
    'models/Activity',
    'leaflet_prunecluster'
], function (_, Backbone, Activity) {

    var ActivityMapLayerView = Backbone.View.extend({
        mapOffset: 60,

        initialize: function (args) {
            this.map = args.map;
            this.activitiesLayer = null;
            this.originalCenter = null;
            this.originalZoom = null;
            this.activityLayer = null;
            this.activityStart = null;
            this.activityEnd = null;
            this.collection = args.collection;
            var CustomIcon = L.Icon.extend({
                options: {
                    iconSize: [33, 50],
                    iconAnchor: [16, 49]
                }
            });
            this.startIcon = new CustomIcon({iconUrl: 'media/pin_start.png'});
            this.endIcon = new CustomIcon({iconUrl: 'media/pin_end.png'});

            this.activitySearch = args.activitySearch;
            this.activitySearch.on('change', this.render, this);
            this.render();
            var _this = this;
            $(window).resize (function () {
                if (_this.map && _this.activityLayer) {
                    _this.map.fitBounds(_this.activityLayer);
                }
            })
        },

        render: function () {
            if (this.activitiesLayer != null && this.map.hasLayer(this.activitiesLayer)) {
                this.map.removeLayer(this.activitiesLayer);
            }
            var returnToSearch = $('.returnToSearch a');
            returnToSearch.unbind('click');
            var _self = this;
            var filteredActivities = [];
            this.collection.each(function(activity) {
                if (_self.activitySearch.filterActivityJson(activity)) {
                    filteredActivities.push(activity);
                }
            });
            // Do not create a markerClusterGroup if the geoJsonLayer map layer is empty.
            if (filteredActivities.length > 0) {
                this.activitiesLayer = new PruneClusterForLeaflet();
                this.activitiesLayer.PrepareLeafletMarker = function (marker, data, category) {
                    var date = new Date(data.startTime);
                    var triggerId = data.activityId;
                    var msg = [];
                    msg.push('' + data.name + '
');
                    msg.push('Start: ' + date.toLocaleDateString() + ' ' + date.toLocaleTimeString() + '
');
                    msg.push('Dist: ' + Math.round((data.totalMeters * 0.000621371) * 100) / 100 + ' mi
');
                    msg.push('Go to Activity');
                    if (marker.getPopup()) {
                        marker.setPopupContent(msg.join(''), data.popupOptions);
                    }
                    else {
                        marker.bindPopup(msg.join(''), data.popupOptions);
                    }
                };
                this.map.addLayer(this.activitiesLayer);
                var marker, minLat, minLon, maxLat, maxLon, lat, lng, coordinates;
                $.each(filteredActivities, function(i, filteredActivity){
                    coordinates = filteredActivity.get('geometry').get('coordinates');
                    lat = coordinates[1];
                    lng = coordinates[0];
                    marker = new PruneCluster.Marker(lat, lng);
                    marker.data = filteredActivity.get('properties').toJSON();
                    _self.activitiesLayer.RegisterMarker(marker);
                    if (typeof minLat == 'undefined' || lat < minLat) {
                        minLat = lat;
                    }
                    if (typeof minLon == 'undefined' || lng < minLon) {
                        minLon = lng;
                    }
                    if (typeof maxLat == 'undefined' || lat > maxLat) {
                        maxLat = lat;
                    }
                    if (typeof maxLon == 'undefined' || lng > maxLon) {
                        maxLon = lng;
                    }
                });

                this.map.on('popupopen', function (event) {
                    _self.onPopupOpen(event);
                });
                returnToSearch.click(function (event) {
                    _self.onReturnToSearch(event)
                });
                if (!isNaN(minLat) && !isNaN(minLon) && !isNaN(maxLat) && !isNaN(maxLon)) {
                    this.map.fitBounds(new L.LatLngBounds(
                        new L.LatLng(minLat, minLon),
                        new L.LatLng(maxLat, maxLon)));
                }
                this.activitiesLayer.ProcessView();
            }
        },

        onEachFeature: function (feature, layer) {
            var date = new Date(feature.properties.startTime);
            var triggerId = feature.properties.activityId;
            var msg = [];
            msg.push('' + feature.properties.name + '
');
            msg.push('Start: ' + date.toLocaleDateString() + ' ' + date.toLocaleTimeString() + '
');
            msg.push('Dist: ' + Math.round((feature.properties.totalMeters * 0.000621371) * 100) / 100 + ' mi
');
            msg.push('Go to Activity');
            layer.bindPopup(msg.join(''), {maxWidth: 200});
        },

        onPopupOpen: function (event) {
            var popup = event.popup;
            var _self = this;
            $(popup._container).on('click', '.popupTrigger', function (event) {
                _self.onOpenActivity(event, popup);
            });

        },

        onOpenActivity: function (event, popup) {
            var location = popup._latlng;
            this.map.closePopup(popup);
            this.originalCenter = this.map.getCenter();
            this.originalZoom = this.map.getZoom();
            this.activity = new Activity({activityId: event.target.id});
            var _this = this;
            this.activity.fetch({
                success: function () {
                    _this.renderActivity();
                },
                error: function (object, xhr, options) {
                    if (console.log && xhr && xhr.responseText) {
                        console.log(xhr.status + " " + xhr.responseText);
                    }
                }
            });
        },

        renderActivity: function () {
            $('#searchBox').slideUp();
            $('.returnToSearch').show();
            if (this.map.hasLayer(this.activitiesLayer)) {
                this.map.removeLayer(this.activitiesLayer);
            }
            $('#demoTitle').html(this.activity.get('properties').get('name'));
            var style = {
                color: '#FF0000',
                weight: 3,
                opacity: 0.6
            };

            this.activityLayer = L.geoJson(this.activity.toJSON(), {style: style}).addTo(this.map);
            var polyline = this.activity.get('geometry').get('coordinates');
            var startPoint = polyline[0];
            var endPoint = polyline[polyline.length - 1];
            this.activityStart = L.marker([startPoint[1], startPoint[0]], {icon: this.startIcon}).addTo(this.map);
            this.activityEnd = L.marker([endPoint[1], endPoint[0]], {icon: this.endIcon}).addTo(this.map);
            var mapBoxDiv = $('.detailsMapBox');
            var top = mapBoxDiv[0].offsetTop;
            var height = mapBoxDiv.height();
            mapBoxDiv.css({top: (top - this.mapOffset) + 'px', height: (height + this.mapOffset) + 'px'});

            var mapDiv = $('.detailMap');
            var mapHeight = mapDiv.height() + this.mapOffset;
            mapDiv.css({height: mapHeight + 'px'});
            this.map.fitBounds(this.activityLayer.getBounds());
        },

        onReturnToSearch: function (event) {
            $('.returnToSearch').hide();
            $('#searchBox').slideDown();
            if (this.activitiesLayer != null) {
                if (this.activityLayer != null && this.map.hasLayer(this.activityLayer)) {
                    this.map.removeLayer(this.activityLayer);
                    this.activityLayer = null;
                }
                if (this.activityStart != null && this.map.hasLayer(this.activityStart)) {
                    this.map.removeLayer(this.activityStart);
                    this.activityStart = null;
                }
                if (this.activityEnd != null && this.map.hasLayer(this.activityEnd)) {
                    this.map.removeLayer(this.activityEnd);
                    this.activityEnd = null
                }
                this.map.addLayer(this.activitiesLayer);
                if (this.originalCenter != null && this.originalZoom != null) {
                    this.map.setView(this.originalCenter, this.originalZoom, {animate: true});
                    this.originalCenter = null;
                    this.originalZoom = null;
                }
                $('#demoTitle').html('Electronic Running Log in GeoJSON Format');
            }
            var mapBoxDiv = $('.detailsMapBox');
            var top = mapBoxDiv[0].offsetTop;
            var height = mapBoxDiv.height();
            mapBoxDiv.css({top: (top + this.mapOffset) + 'px', height: (height - this.mapOffset) + 'px'});

            var mapDiv = $('.detailMap');
            var mapHeight = mapDiv.height();
            mapDiv.css({top: '5px', height: (mapHeight - this.mapOffset) + 'px'});
        },

        destroy: function () {
            $('.returnToSearch a').unbind('click');
            // Remove view from DOM
            this.remove();
        }

    });

    return ActivityMapLayerView;
});
<commit_msg>Added guard condtion to prevent error in Demo 5.<commit_after>/**
 * The purpose of the ActivityMapLayerView is render feature collection GeoJson on the map.
 */
define([
    'underscore',
    'backbone',
    'models/Activity',
    'leaflet_prunecluster'
], function (_, Backbone, Activity) {

    var ActivityMapLayerView = Backbone.View.extend({
        mapOffset: 60,

        initialize: function (args) {
            this.map = args.map;
            this.activitiesLayer = null;
            this.originalCenter = null;
            this.originalZoom = null;
            this.activityLayer = null;
            this.activityStart = null;
            this.activityEnd = null;
            this.collection = args.collection;
            var CustomIcon = L.Icon.extend({
                options: {
                    iconSize: [33, 50],
                    iconAnchor: [16, 49]
                }
            });
            this.startIcon = new CustomIcon({iconUrl: 'media/pin_start.png'});
            this.endIcon = new CustomIcon({iconUrl: 'media/pin_end.png'});

            this.activitySearch = args.activitySearch;
            this.activitySearch.on('change', this.render, this);
            this.render();
            var _this = this;
            $(window).resize (function () {
                if (_this.map && _this.activityLayer) {
                    _this.map.fitBounds(_this.activityLayer);
                }
            })
        },

        render: function () {
            if (this.activitiesLayer != null && this.map.hasLayer(this.activitiesLayer)) {
                this.map.removeLayer(this.activitiesLayer);
            }
            var returnToSearch = $('.returnToSearch a');
            returnToSearch.unbind('click');
            var _self = this;
            var filteredActivities = [];
            this.collection.each(function(activity) {
                if (_self.activitySearch.filterActivityJson(activity)) {
                    filteredActivities.push(activity);
                }
            });
            // Do not create a markerClusterGroup if the geoJsonLayer map layer is empty.
            if (filteredActivities.length > 0) {
                this.activitiesLayer = new PruneClusterForLeaflet();
                this.activitiesLayer.PrepareLeafletMarker = function (marker, data, category) {
                    var date = new Date(data.startTime);
                    var triggerId = data.activityId;
                    var msg = [];
                    msg.push('' + data.name + '
');
                    msg.push('Start: ' + date.toLocaleDateString() + ' ' + date.toLocaleTimeString() + '
');
                    msg.push('Dist: ' + Math.round((data.totalMeters * 0.000621371) * 100) / 100 + ' mi
');
                    msg.push('Go to Activity');
                    if (marker.getPopup()) {
                        marker.setPopupContent(msg.join(''), data.popupOptions);
                    }
                    else {
                        marker.bindPopup(msg.join(''), data.popupOptions);
                    }
                };
                this.map.addLayer(this.activitiesLayer);
                var marker, minLat, minLon, maxLat, maxLon, lat, lng, coordinates;
                $.each(filteredActivities, function(i, filteredActivity){
                    coordinates = filteredActivity.get('geometry').get('coordinates');
                    lat = coordinates[1];
                    lng = coordinates[0];
                    marker = new PruneCluster.Marker(lat, lng);
                    marker.data = filteredActivity.get('properties').toJSON();
                    _self.activitiesLayer.RegisterMarker(marker);
                    if (typeof minLat == 'undefined' || lat < minLat) {
                        minLat = lat;
                    }
                    if (typeof minLon == 'undefined' || lng < minLon) {
                        minLon = lng;
                    }
                    if (typeof maxLat == 'undefined' || lat > maxLat) {
                        maxLat = lat;
                    }
                    if (typeof maxLon == 'undefined' || lng > maxLon) {
                        maxLon = lng;
                    }
                });

                this.map.on('popupopen', function (event) {
                    _self.onPopupOpen(event);
                });
                returnToSearch.click(function (event) {
                    _self.onReturnToSearch(event)
                });
                if (!isNaN(minLat) && !isNaN(minLon) && !isNaN(maxLat) && !isNaN(maxLon)) {
                    this.map.fitBounds(new L.LatLngBounds(
                        new L.LatLng(minLat, minLon),
                        new L.LatLng(maxLat, maxLon)));
                }
                this.activitiesLayer.ProcessView();
            }
        },

        onEachFeature: function (feature, layer) {
            var date = new Date(feature.properties.startTime);
            var triggerId = feature.properties.activityId;
            var msg = [];
            msg.push('' + feature.properties.name + '
');
            msg.push('Start: ' + date.toLocaleDateString() + ' ' + date.toLocaleTimeString() + '
');
            msg.push('Dist: ' + Math.round((feature.properties.totalMeters * 0.000621371) * 100) / 100 + ' mi
');
            msg.push('Go to Activity');
            layer.bindPopup(msg.join(''), {maxWidth: 200});
        },

        onPopupOpen: function (event) {
            var popup = event.popup;
            var _self = this;
            $(popup._container).on('click', '.popupTrigger', function (event) {
                _self.onOpenActivity(event, popup);
            });

        },

        onOpenActivity: function (event, popup) {
            var location = popup._latlng;
            this.map.closePopup(popup);
            this.originalCenter = this.map.getCenter();
            this.originalZoom = this.map.getZoom();
            this.activity = new Activity({activityId: event.target.id});
            var _this = this;
            this.activity.fetch({
                success: function () {
                    _this.renderActivity();
                },
                error: function (object, xhr, options) {
                    if (console.log && xhr && xhr.responseText) {
                        console.log(xhr.status + " " + xhr.responseText);
                    }
                }
            });
        },

        renderActivity: function () {
            $('#searchBox').slideUp();
            $('.returnToSearch').show();
            if (this.map.hasLayer(this.activitiesLayer)) {
                this.map.removeLayer(this.activitiesLayer);
            }
            if (this.activity.get('properties')) {
                $('#demoTitle').html(this.activity.get('properties').get('name'));
            }
            var style = {
                color: '#FF0000',
                weight: 3,
                opacity: 0.6
            };

            this.activityLayer = L.geoJson(this.activity.toJSON(), {style: style}).addTo(this.map);
            var polyline = this.activity.get('geometry').get('coordinates');
            var startPoint = polyline[0];
            var endPoint = polyline[polyline.length - 1];
            this.activityStart = L.marker([startPoint[1], startPoint[0]], {icon: this.startIcon}).addTo(this.map);
            this.activityEnd = L.marker([endPoint[1], endPoint[0]], {icon: this.endIcon}).addTo(this.map);
            var mapBoxDiv = $('.detailsMapBox');
            var top = mapBoxDiv[0].offsetTop;
            var height = mapBoxDiv.height();
            mapBoxDiv.css({top: (top - this.mapOffset) + 'px', height: (height + this.mapOffset) + 'px'});

            var mapDiv = $('.detailMap');
            var mapHeight = mapDiv.height() + this.mapOffset;
            mapDiv.css({height: mapHeight + 'px'});
            this.map.fitBounds(this.activityLayer.getBounds());
        },

        onReturnToSearch: function (event) {
            $('.returnToSearch').hide();
            $('#searchBox').slideDown();
            if (this.activitiesLayer != null) {
                if (this.activityLayer != null && this.map.hasLayer(this.activityLayer)) {
                    this.map.removeLayer(this.activityLayer);
                    this.activityLayer = null;
                }
                if (this.activityStart != null && this.map.hasLayer(this.activityStart)) {
                    this.map.removeLayer(this.activityStart);
                    this.activityStart = null;
                }
                if (this.activityEnd != null && this.map.hasLayer(this.activityEnd)) {
                    this.map.removeLayer(this.activityEnd);
                    this.activityEnd = null
                }
                this.map.addLayer(this.activitiesLayer);
                if (this.originalCenter != null && this.originalZoom != null) {
                    this.map.setView(this.originalCenter, this.originalZoom, {animate: true});
                    this.originalCenter = null;
                    this.originalZoom = null;
                }
                $('#demoTitle').html('Electronic Running Log in GeoJSON Format');
            }
            var mapBoxDiv = $('.detailsMapBox');
            var top = mapBoxDiv[0].offsetTop;
            var height = mapBoxDiv.height();
            mapBoxDiv.css({top: (top + this.mapOffset) + 'px', height: (height - this.mapOffset) + 'px'});

            var mapDiv = $('.detailMap');
            var mapHeight = mapDiv.height();
            mapDiv.css({top: '5px', height: (mapHeight - this.mapOffset) + 'px'});
        },

        destroy: function () {
            $('.returnToSearch a').unbind('click');
            // Remove view from DOM
            this.remove();
        }

    });

    return ActivityMapLayerView;
});
<|endoftext|>


<commit_before>import Joi from '@hapi/joi'

const dateTimeSchema = Joi.array().min(3).max(7).ordered(
  Joi.number().integer(),
  Joi.number().integer().min(1).max(12),
  Joi.number().integer().min(1).max(31),
  Joi.number().integer().min(0).max(23),
  Joi.number().integer().min(0).max(60),
  Joi.number().integer().min(0).max(60)
)

const durationSchema = Joi.object().keys({
  before: Joi.boolean(),//option to set before alaram
  weeks: Joi.number(),
  days: Joi.number(),
  hours: Joi.number(),
  minutes: Joi.number(),
  seconds: Joi.number()
})

const contactSchema = Joi.object().keys({
  name: Joi.string(),
  email: Joi.string().email(),
  rsvp: Joi.boolean(),
  dir: Joi.string().uri(),
  partstat: Joi.string(),
  role: Joi.string()
})

const organizerSchema = Joi.object().keys({
  name: Joi.string(),
  email: Joi.string().email()
})

const alarmSchema = Joi.object().keys({
  action: Joi.string().regex(/audio|display|email/).required(),
  trigger: Joi.any().required(),
  description: Joi.string(),
  duration: durationSchema,
  repeat: Joi.number(),
  attach: Joi.string(),
  attachType: Joi.string(),
  summary: Joi.string(),
  attendee: contactSchema,
  'x-prop': Joi.any(),
  'iana-prop': Joi.any()
})

const schema = Joi.object().keys({
  summary: Joi.string(),
  timestamp: Joi.any(),
  title: Joi.string(),
  busy: Joi.bool(),
  productId: Joi.string(),
  method: Joi.string(),
  uid: Joi.string().required(),
  sequence: Joi.number(),
  start: dateTimeSchema.required(),
  duration: durationSchema,
  startType: Joi.string().regex(/utc|local/),
  startInputType: Joi.string().regex(/utc|local/),
  startOutputType: Joi.string().regex(/utc|local/),
  end: dateTimeSchema,
  endInputType: Joi.string().regex(/utc|local/),
  endOutputType: Joi.string().regex(/utc|local/),
  description: Joi.string(),
  url: Joi.string().uri(),
  geo: Joi.object().keys({ lat: Joi.number(), lon: Joi.number() }),
  location: Joi.string(),
  status: Joi.string().regex(/TENTATIVE|CANCELLED|CONFIRMED/),
  categories: Joi.array().items(Joi.string()),
  organizer: organizerSchema,
  attendees: Joi.array().items(contactSchema),
  alarms: Joi.array().items(alarmSchema),
  recurrenceRule: Joi.string(),
}).xor('end', 'duration')

export default function validateEvent(candidate) {
  const { error, value } = Joi.validate(candidate, schema)
  return { error, value }
}
<commit_msg>fixing schema<commit_after>import Joi from '@hapi/joi'

const dateTimeSchema = Joi.array().min(3).max(7).ordered(
  Joi.number().integer(),
  Joi.number().integer().min(1).max(12),
  Joi.number().integer().min(1).max(31),
  Joi.number().integer().min(0).max(23),
  Joi.number().integer().min(0).max(60),
  Joi.number().integer().min(0).max(60)
)

const durationSchema = Joi.object().keys({
  before: Joi.boolean(),//option to set before alaram
  weeks: Joi.number(),
  days: Joi.number(),
  hours: Joi.number(),
  minutes: Joi.number(),
  seconds: Joi.number()
})

const contactSchema = Joi.object().keys({
  name: Joi.string(),
  email: Joi.string().email(),
  rsvp: Joi.boolean(),
  dir: Joi.string().uri(),
  partstat: Joi.string(),
  role: Joi.string()
})

const organizerSchema = Joi.object().keys({
  name: Joi.string(),
  email: Joi.string().email()
})

const alarmSchema = Joi.object().keys({
  action: Joi.string().regex(/audio|display|email/).required(),
  trigger: Joi.any().required(),
  description: Joi.string(),
  duration: durationSchema,
  repeat: Joi.number(),
  attach: Joi.string(),
  attachType: Joi.string(),
  summary: Joi.string(),
  attendee: contactSchema,
  'x-prop': Joi.any(),
  'iana-prop': Joi.any()
})

const schema = Joi.object().keys({
  summary: Joi.string(),
  timestamp: Joi.any(),
  title: Joi.string(),
  productId: Joi.string(),
  method: Joi.string(),
  uid: Joi.string().required(),
  sequence: Joi.number(),
  start: dateTimeSchema.required(),
  duration: durationSchema,
  startType: Joi.string().regex(/utc|local/),
  startInputType: Joi.string().regex(/utc|local/),
  startOutputType: Joi.string().regex(/utc|local/),
  end: dateTimeSchema,
  endInputType: Joi.string().regex(/utc|local/),
  endOutputType: Joi.string().regex(/utc|local/),
  description: Joi.string(),
  url: Joi.string().uri(),
  geo: Joi.object().keys({ lat: Joi.number(), lon: Joi.number() }),
  location: Joi.string(),
  status: Joi.string().regex(/TENTATIVE|CANCELLED|CONFIRMED/),
  categories: Joi.array().items(Joi.string()),
  organizer: organizerSchema,
  attendees: Joi.array().items(contactSchema),
  alarms: Joi.array().items(alarmSchema),
  recurrenceRule: Joi.string(),
  busyStatus: Joi.string().regex(/TENTATIVE|FREE|BUSY|OOF/),
}).xor('end', 'duration')

export default function validateEvent(candidate) {
  const { error, value } = Joi.validate(candidate, schema)
  return { error, value }
}
<|endoftext|>


<commit_before>/* MOK-JS v1.0.0 */
if(!this.mok){
	var mok = {}, require = function(){
		var m = mok, done = {};
		return function(id){
			if(done.hasOwnProperty(id)){
				return done[id];
			}
			done[id] = function(){}; //jiandan-cubao-di break circular dependency
			var x = m[id], module = {id:id, exports:{}};
			x(require, module, module.exports);
			m[id] = null;
			return done[id] = module.exports;
		}
	}();
	this.global || (global = this);
}
<commit_msg>Delete br-mok-node.js<commit_after><|endoftext|>


<commit_before>var binding         = require('./binding').vad,        // native bindings
    inherits        = require('util').inherits,
    EventEmitter    = require('events').EventEmitter

/**
 * @api public
 * Utility function that converts a buffer to a ES float array
 * @param {Buffer} buffer Node buffer containing binary float32 data
 * @returns {Float32Array} TypedArray from buffer object
 */
function toFloatArray(buffer) {

    if (!buffer || !buffer.length) {
        return new Float32Array()
    }

    if (buffer.toArrayBuffer) {
        // Node 0.12+
        return new Float32Array(buffer.toArrayBuffer())
    } else {
        // Node <0.12
        var len = buffer.length, i,
            arrayBuffer = new ArrayBuffer(len),
            view = new Uint8Array(arrayBuffer)

        for (i = 0; i < len; ++i) {
            view[i] = buffer[i]
        }

        return new Float32Array(arrayBuffer)
    }
}

/**
 * @api public
 * @class
 * Provides simple Voice Activity Detection
 * @param {Number} [mode] Voice detection mode
 */
function VAD(mode) {
    if (!(this instanceof VAD)) {
        throw new Error('Must be called with "new"')
    }

    var res = binding.vad_alloc(null)
    if (res.error) {
        throw new Error('Failed to get VAD size')
    }

    this._vad = new Buffer(res.size)
    res = binding.vad_alloc(this._vad)
    if (!res) {
        throw new Error('Failed to allocate VAD')
    }

    res = binding.vad_init(this._vad)
    if (!res) {
        throw new Error('Failed to initialise VAD')
    }

    if (typeof mode === 'number' &&
        mode >= VAD.MODE_NORMAL && mode <= VAD.MODE_VERY_AGGRESSIVE) {
        binding.vad_setmode(this._vad, mode)
    } else if (typeof mode !== 'undefined') {
        throw new Error('Invalid mode settings')
    }

    this._processQueue = []
}

inherits(VAD, EventEmitter)

/**
 * @api public
 * @static
 * @readonly
 * @property {Number} VAD.EVENT_ERROR   Constant for VAD error event
 * @property {Number} VAD.EVENT_SILENCE Constant for VAD silence event
 * @property {Number} VAD.EVENT_VOICE   Constant for VAD voice event
 * @property {Number} VAD.EVENT_NOISE   Constant for VAD noise event [not supported yet]
 */
Object.defineProperty(VAD, 'EVENT_ERROR',   { value: -1, writable: false })
Object.defineProperty(VAD, 'EVENT_SILENCE', { value: 0, writable: false })
Object.defineProperty(VAD, 'EVENT_VOICE',   { value: 1, writable: false })
Object.defineProperty(VAD, 'EVENT_NOISE',   { value: 2, writable: false })

/**
 * @api public
 * @static
 * @readonly
 * @property {Number} VAD.MODE_NORMAL           Constant for normal voice detection mode
 * @property {Number} VAD.MODE_LOW_BITRATE      Constant for low bitrate voice detection mode
 * @property {Number} VAD.MODE_AGGRESSIVE       Constant for aggressive voice detection mode
 * @property {Number} VAD.MODE_VERY_AGGRESSIVE  Constant for very aggressive voice detection mode
 */
Object.defineProperty(VAD, 'MODE_NORMAL',          { value: 0, writable: false })
Object.defineProperty(VAD, 'MODE_LOW_BITRATE',     { value: 1, writable: false })
Object.defineProperty(VAD, 'MODE_AGGRESSIVE',      { value: 2, writable: false })
Object.defineProperty(VAD, 'MODE_VERY_AGGRESSIVE', { value: 3, writable: false })

/**
 * @api private
 * @function
 * Processes the next item in the processing queue
 */
VAD.prototype._dequeueItem = function() {
    var EVENT_MAP = ['error', 'silence', 'voice', 'noise']

    function evaluateAndDequeueNext(err, res) {
        var item = this._processQueue.shift(),
            index = res + 1

        this.emit('event', res)

        if (index >= 0 && index < EVENT_MAP.length) {
            this.emit(EVENT_MAP[index], res)
        }

        try {
            item.callback(err, res)
        } catch(e) {
            this.emit('error', e)
        }

        // continue on the next tick
        process.nextTick(this._dequeueItem.bind(this))
    }

    if (this._processQueue.length > 0) {
        var entry = this._processQueue[0]
        binding.vad_processAudio(this._vad, entry.samples, entry.rate,
            evaluateAndDequeueNext.bind(this))
    }
}

/**
 * @api public
 * @function
 * Analyses the given buffer and returns voice or silence.
 *
 * @param    {Buffer}            samples     Signal to analyse (containing normalised float samples)
 * @param    {Number}            samplerate  Sample rate of the signal in Hz
 * @param    {VAD~asyncCallback} callback    Async callback that is invoked after completion
 */
VAD.prototype.processAudio = function(samples, samplerate, callback) {
    if (!callback || typeof callback !== 'function') {
        throw new Error('Callback must be a function')
    }

    this._processQueue.push({ samples: samples, rate: samplerate, callback: callback })

    if (this._processQueue.length === 1) {
        this._dequeueItem()
    }
}

/**
 * @api public
 * @function
 * Creates a new Voice Activity Detection object
 *
 * @param {Number} [mode] Voice detection mode
 * @returns {VAD}
 */
function createVAD(mode) {
    return VAD(mode)
}

/**
 * This callback notifies the detected voice event for the processed audio.
 * @callback VAD~asyncCallback
 * @param {Object|Null} error    Error that occurred during the operation
 * @param {VoiceEvent}  result   VAD event that was generated by the audio
 */

module.exports = {
    VAD:            VAD,
    createVAD:      createVAD,
    toFloatArray:   toFloatArray
}<commit_msg>Bugfix: the factory function createVAD threw an exception<commit_after>var binding         = require('./binding').vad,        // native bindings
    inherits        = require('util').inherits,
    EventEmitter    = require('events').EventEmitter

/**
 * @api public
 * Utility function that converts a buffer to a ES float array
 * @param {Buffer} buffer Node buffer containing binary float32 data
 * @returns {Float32Array} TypedArray from buffer object
 */
function toFloatArray(buffer) {

    if (!buffer || !buffer.length) {
        return new Float32Array()
    }

    if (buffer.toArrayBuffer) {
        // Node 0.12+
        return new Float32Array(buffer.toArrayBuffer())
    } else {
        // Node <0.12
        var len = buffer.length, i,
            arrayBuffer = new ArrayBuffer(len),
            view = new Uint8Array(arrayBuffer)

        for (i = 0; i < len; ++i) {
            view[i] = buffer[i]
        }

        return new Float32Array(arrayBuffer)
    }
}

/**
 * @api public
 * @class
 * Provides simple Voice Activity Detection
 * @param {Number} [mode] Voice detection mode
 */
function VAD(mode) {
    if (!(this instanceof VAD)) {
        throw new Error('Must be called with "new"')
    }

    var res = binding.vad_alloc(null)
    if (res.error) {
        throw new Error('Failed to get VAD size')
    }

    this._vad = new Buffer(res.size)
    res = binding.vad_alloc(this._vad)
    if (!res) {
        throw new Error('Failed to allocate VAD')
    }

    res = binding.vad_init(this._vad)
    if (!res) {
        throw new Error('Failed to initialise VAD')
    }

    if (typeof mode === 'number' &&
        mode >= VAD.MODE_NORMAL && mode <= VAD.MODE_VERY_AGGRESSIVE) {
        binding.vad_setmode(this._vad, mode)
    } else if (typeof mode !== 'undefined') {
        throw new Error('Invalid mode settings')
    }

    this._processQueue = []
}

inherits(VAD, EventEmitter)

/**
 * @api public
 * @static
 * @readonly
 * @property {Number} VAD.EVENT_ERROR   Constant for VAD error event
 * @property {Number} VAD.EVENT_SILENCE Constant for VAD silence event
 * @property {Number} VAD.EVENT_VOICE   Constant for VAD voice event
 * @property {Number} VAD.EVENT_NOISE   Constant for VAD noise event [not supported yet]
 */
Object.defineProperty(VAD, 'EVENT_ERROR',   { value: -1, writable: false })
Object.defineProperty(VAD, 'EVENT_SILENCE', { value: 0, writable: false })
Object.defineProperty(VAD, 'EVENT_VOICE',   { value: 1, writable: false })
Object.defineProperty(VAD, 'EVENT_NOISE',   { value: 2, writable: false })

/**
 * @api public
 * @static
 * @readonly
 * @property {Number} VAD.MODE_NORMAL           Constant for normal voice detection mode
 * @property {Number} VAD.MODE_LOW_BITRATE      Constant for low bitrate voice detection mode
 * @property {Number} VAD.MODE_AGGRESSIVE       Constant for aggressive voice detection mode
 * @property {Number} VAD.MODE_VERY_AGGRESSIVE  Constant for very aggressive voice detection mode
 */
Object.defineProperty(VAD, 'MODE_NORMAL',          { value: 0, writable: false })
Object.defineProperty(VAD, 'MODE_LOW_BITRATE',     { value: 1, writable: false })
Object.defineProperty(VAD, 'MODE_AGGRESSIVE',      { value: 2, writable: false })
Object.defineProperty(VAD, 'MODE_VERY_AGGRESSIVE', { value: 3, writable: false })

/**
 * @api private
 * @function
 * Processes the next item in the processing queue
 */
VAD.prototype._dequeueItem = function() {
    var EVENT_MAP = ['error', 'silence', 'voice', 'noise']

    function evaluateAndDequeueNext(err, res) {
        var item = this._processQueue.shift(),
            index = res + 1

        this.emit('event', res)

        if (index >= 0 && index < EVENT_MAP.length) {
            this.emit(EVENT_MAP[index], res)
        }

        try {
            item.callback(err, res)
        } catch(e) {
            this.emit('error', e)
        }

        // continue on the next tick
        process.nextTick(this._dequeueItem.bind(this))
    }

    if (this._processQueue.length > 0) {
        var entry = this._processQueue[0]
        binding.vad_processAudio(this._vad, entry.samples, entry.rate,
            evaluateAndDequeueNext.bind(this))
    }
}

/**
 * @api public
 * @function
 * Analyses the given buffer and returns voice or silence.
 *
 * @param    {Buffer}            samples     Signal to analyse (containing normalised float samples)
 * @param    {Number}            samplerate  Sample rate of the signal in Hz
 * @param    {VAD~asyncCallback} callback    Async callback that is invoked after completion
 */
VAD.prototype.processAudio = function(samples, samplerate, callback) {
    if (!callback || typeof callback !== 'function') {
        throw new Error('Callback must be a function')
    }

    this._processQueue.push({ samples: samples, rate: samplerate, callback: callback })

    if (this._processQueue.length === 1) {
        this._dequeueItem()
    }
}

/**
 * @api public
 * @function
 * Creates a new Voice Activity Detection object
 *
 * @param {Number} [mode] Voice detection mode
 * @returns {VAD}
 */
function createVAD(mode) {
    return new VAD(mode)
}

/**
 * This callback notifies the detected voice event for the processed audio.
 * @callback VAD~asyncCallback
 * @param {Object|Null} error    Error that occurred during the operation
 * @param {VoiceEvent}  result   VAD event that was generated by the audio
 */

module.exports = {
    VAD:            VAD,
    createVAD:      createVAD,
    toFloatArray:   toFloatArray
}
<|endoftext|>


<commit_before>var params, scene, camera, renderer, stats, gui, controls;

init();
animate();

function init() {
    // Params
    params = {
        'Number of snowflakes': 1000,
        'Snowflake size': 0.1,
        'Downward motion': 5,
        'Brownian motion': 2,
        'Melting factor': 0.05,
        'Step size': 0.01,
        'Scene size': 15,
        'Show floor': true,
        'Show box': true,
        'Show sphere': false
    };

    // Scene
    scene = new THREE.Scene();
    scene.fog = new THREE.Fog(0x111111, 1, 50);

    // Lights
    lights.forEach(light => scene.add(light));

    // Objects
    objects.forEach(object => scene.add(object));

    // Snowflakes
    for (let i = 0; i < params['Number of snowflakes']; i++) {
        snowflakes[i] = new Snowflake();
    }

    // Camera
    camera = new THREE.PerspectiveCamera(
        60,
        window.innerWidth / window.innerHeight,
        1,
        100
    );
    camera.position.set(-3, 2, -4);

    // Renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0x111111, 1);
    renderer.shadowMap.enabled = true;
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // Stats
    stats = new Stats();
    document.body.appendChild(stats.dom);

    // GUI
    gui = new dat.GUI({ width: 350 });
    var snowflakesFolder = gui.addFolder('Snowflakes');
    snowflakesFolder.open();
    var sceneFolder = gui.addFolder('Scene');
    sceneFolder.open();

    snowflakesFolder
        .add(params, 'Number of snowflakes', 0, 5000)
        .step(1)
        .onChange(val => {
            let delta = val - snowflakes.length;
            console.log(delta);
            if (delta < 0) {
                // Remove snowflakes
                for (let i = 0; i < -1 * delta; i++) {
                    console.log('remove ' + i);
                    scene.remove(snowflakes[i].sprite);
                }
                snowflakes.splice(0, -1 * delta);
            } else {
                // Add snowflakes
                for (let i = 0; i < delta; i++) {
                    console.log('add ' + snowflakes.length);
                    snowflakes.push(new Snowflake());
                }
            }
            params['Number of snowflakes'] = val;
        });
    snowflakesFolder
        .add(params, 'Snowflake size', 0, 0.2)
        .onChange(val => (params['Snowflake size'] = val));
    snowflakesFolder
        .add(params, 'Downward motion', 0, 10)
        .onChange(val => (params['Downward motion'] = val));
    snowflakesFolder
        .add(params, 'Brownian motion', 0, 10)
        .onChange(val => (params['Brownian motion'] = val));
    snowflakesFolder
        .add(params, 'Melting factor', 0, 0.5)
        .onChange(val => (params['Melting factor'] = val));
    snowflakesFolder
        .add(params, 'Step size', 0.005, 0.015)
        .onChange(val => (params['Step size'] = val));

    sceneFolder
        .add(params, 'Scene size', 0, 30)
        .onChange(val => (params['Scene size'] = val));
    sceneFolder
        .add(params, 'Show floor')
        .onChange(val => {
            val ? scene.add(floor) : scene.remove(floor);
            params['Show floor'] = val;
        });
    sceneFolder
        .add(params, 'Show box')
        .onChange(val => {
            val ? scene.add(box) : scene.remove(box);
            params['Show box'] = val;
        });
    sceneFolder
        .add(params, 'Show sphere')
        .onChange(val => {
            val ? scene.add(sphere) : scene.remove(sphere);
            params['Show sphere'] = val;
        });

    // Controls
    controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.5;
    controls.enableZoom = true;

    // Resize
    window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    snowflakes.forEach(snowflake => snowflake.update());

    requestAnimationFrame(animate);

    controls.update();

    stats.update();

    renderer.render(scene, camera);
}

<commit_msg>Increase default snowflake count<commit_after>var params, scene, camera, renderer, stats, gui, controls;

init();
animate();

function init() {
    // Params
    params = {
        'Number of snowflakes': 2000,
        'Snowflake size': 0.1,
        'Downward motion': 5,
        'Brownian motion': 2,
        'Melting factor': 0.05,
        'Step size': 0.01,
        'Scene size': 15,
        'Show floor': true,
        'Show box': true,
        'Show sphere': false
    };

    // Scene
    scene = new THREE.Scene();
    scene.fog = new THREE.Fog(0x111111, 1, 50);

    // Lights
    lights.forEach(light => scene.add(light));

    // Objects
    objects.forEach(object => scene.add(object));

    // Snowflakes
    for (let i = 0; i < params['Number of snowflakes']; i++) {
        snowflakes[i] = new Snowflake();
    }

    // Camera
    camera = new THREE.PerspectiveCamera(
        60,
        window.innerWidth / window.innerHeight,
        1,
        100
    );
    camera.position.set(-3, 2, -4);

    // Renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0x111111, 1);
    renderer.shadowMap.enabled = true;
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // Stats
    stats = new Stats();
    document.body.appendChild(stats.dom);

    // GUI
    gui = new dat.GUI({ width: 350 });
    var snowflakesFolder = gui.addFolder('Snowflakes');
    snowflakesFolder.open();
    var sceneFolder = gui.addFolder('Scene');
    sceneFolder.open();

    snowflakesFolder
        .add(params, 'Number of snowflakes', 0, 5000)
        .step(1)
        .onChange(val => {
            let delta = val - snowflakes.length;
            console.log(delta);
            if (delta < 0) {
                // Remove snowflakes
                for (let i = 0; i < -1 * delta; i++) {
                    console.log('remove ' + i);
                    scene.remove(snowflakes[i].sprite);
                }
                snowflakes.splice(0, -1 * delta);
            } else {
                // Add snowflakes
                for (let i = 0; i < delta; i++) {
                    console.log('add ' + snowflakes.length);
                    snowflakes.push(new Snowflake());
                }
            }
            params['Number of snowflakes'] = val;
        });
    snowflakesFolder
        .add(params, 'Snowflake size', 0, 0.2)
        .onChange(val => (params['Snowflake size'] = val));
    snowflakesFolder
        .add(params, 'Downward motion', 0, 10)
        .onChange(val => (params['Downward motion'] = val));
    snowflakesFolder
        .add(params, 'Brownian motion', 0, 10)
        .onChange(val => (params['Brownian motion'] = val));
    snowflakesFolder
        .add(params, 'Melting factor', 0, 0.5)
        .onChange(val => (params['Melting factor'] = val));
    snowflakesFolder
        .add(params, 'Step size', 0.005, 0.015)
        .onChange(val => (params['Step size'] = val));

    sceneFolder
        .add(params, 'Scene size', 0, 30)
        .onChange(val => (params['Scene size'] = val));
    sceneFolder
        .add(params, 'Show floor')
        .onChange(val => {
            val ? scene.add(floor) : scene.remove(floor);
            params['Show floor'] = val;
        });
    sceneFolder
        .add(params, 'Show box')
        .onChange(val => {
            val ? scene.add(box) : scene.remove(box);
            params['Show box'] = val;
        });
    sceneFolder
        .add(params, 'Show sphere')
        .onChange(val => {
            val ? scene.add(sphere) : scene.remove(sphere);
            params['Show sphere'] = val;
        });

    // Controls
    controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.5;
    controls.enableZoom = true;

    // Resize
    window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    snowflakes.forEach(snowflake => snowflake.update());

    requestAnimationFrame(animate);

    controls.update();

    stats.update();

    renderer.render(scene, camera);
}

<|endoftext|>


<commit_before>var utils = require('../utils'),
    util = utils.util,
    _u = require('underscore');

var update = module.exports = function(app, queryId, change_json_file) {

    var accepted_change_types = {
        override: "override",
        addition: "addition",
        replace: "replace"
    };
    var Query, Rules, current_rule;

    /** Open and use existing Session for MD-Record(s) submission */
    var openSession = function(session, callback) {
        app.session = session;
        app.log.info("Using existing Session-" + app.session.id);

        return callback(queryId);
    }

    var getQuery = function(queryId) {
        if (queryId.length != 24) throw new Error("Query Id is invalid.");
        app.schema.models.Query.findById(queryId).populate({
            path: '_session',
            select: '_id'
        }).populate("result_collection", null, {
            "status.completed": false
        }).exec(function(err, query) {
            if (err) throw err;
            if (query != null && query._session.id == app.session.id.toString()) {
                Query = query;
                app.log.info("Found query: " + Query.id);
                app.log.info("Applying change-rule(s)...");
                utils.loadJSONFile(change_json_file, function(rules) {
                    if (util.isArray(rules))
                        app.log.debug('One or more rules to apply.');
                    else
                        throw new Error('Illegal change-rule syntax: Should be Array.');

                    Rules = rules; // set global
                    nextRule(); //exec first rule
                });
            } else {
                throw new Error("No Query found for Session: " + app.session.id);
            }
        });
    }

    var nextRule = function() {
        var current_index = (current_rule != null) ? _u.indexOf(Rules, current_rule) : 0;
        if (current_rule != null) current_index++;
        if (current_index < Rules.length) {
            app.log.info("Executing rule (" + current_index + ")...");
            applyChangeRules(Rules[current_index]);
        } else {
            utils.updateQuery(Query, function() {
                process.nextTick(function() {
                    process.exit(0);
                });
            });
        }
    }

    var applyChangeRules = function(rule) {
        current_rule = rule;
        //For each rule apply to query.result_collection
        var results = Query.result_collection;
        for (var i = 0; i < results.length; i++) {
            var mdrecord = results[i];
            if (mdrecord != null) {
                applyChangeRule(mdrecord, rule);
            }
        }

        process.nextTick(nextRule);
    }

    var applyChangeRule = function(mdrecord, rule) {
        switch (rule.change_type) {
            case accepted_change_types.override:
                applyChangeOverride(mdrecord, rule);
                break;
            case accepted_change_types.addition:
                applyChangeAddition(mdrecord, rule);
                break;
            case accepted_change_types.replace:
                applyChangeReplace(mdrecord, rule);
                break;
                //TODO define deletion rule
            default:
                app.log.warn("Illegel change-rule syntax: Change type " + change_type + " unsupported.")
        }
    }

    var applyChangeReplace = function(mdrecord, rule) {
        app.log.info("Applying replace rule...");
        var d = JSON.parse(mdrecord.data); //parse JSON record

        // find node to edit, check against conditions if they exist in config rule and replace with a match condition if exists
        var newAttr = (rule.add_attr != undefined) ? rule.add_attr : false;
        findFieldPosition(d, rule.field_position, rule.selector, false, newAttr, function(data) {
            var field, val, match, cond_pair = (rule.conditions != null) ? _u.pairs(rule.conditions) : null;
            //Parse over one or more-conditions
            //Note: Better validation if conditions value exists
            if (cond_pair != null && util.isArray(cond_pair)) {
                for (var i = 0; i < cond_pair.length; i++) {
                    field = cond_pair[i][0], val = cond_pair[i][1];
                    if (field != undefined && val != undefined)
                        if (field == "$match")
                            match = val;
                        else if ((field == "_" && data[field] != val) || (field != "_" && data["$"][field] != val))
                            return data[rule.selector]; //unchanged value if condition doesn't match
                        else app.log.info('Condition match found for query field: ' + field);
                }
            }

            // replace values in data string
            app.log.debug('Replacing str "' + match + '" with "' + rule.set_value + '" on "' + util.inspect(data) + '" + sel:' + rule.selector);
            if (match != null || match != undefined)
                return data[rule.selector].replace(match, rule.set_value);
            else
                return rule.set_value; // set new value with replace() match if passes all conditions, if the field exists in change config file

        });

        process.nextTick(function() {
            utils.updateMDRecord(d, mdrecord);
        });

    }

    var applyChangeAddition = function(mdrecord, rule) {
        app.log.info("Applying addition rule...");

        var d = JSON.parse(mdrecord.data); // parse JSON record

        // Add new field to MD-record
        findFieldPosition(d, rule.field_position, null, true, false, function(data, existingNode) {
            var newNode;
            //app.log.debug('call callback addition:' + util.inspect(existingNode));
            if (existingNode != null) {
                newNode = new Array(2);
                newNode[0] = existingNode;
                newNode[1] = _u.extend(data, rule.properties);
            } else {
                newNode = _u.extend(data, rule.properties);
            }

            return newNode;
        });

        process.nextTick(function() {
            utils.updateMDRecord(d, mdrecord);
        });
    }

    var applyChangeOverride = function(mdrecord, rule) {
        app.log.info("Applying override rule...");

        var d = JSON.parse(mdrecord.data); // parse JSON record

        // find node to edit, check against conditions if they exist in config rules
        var newAttr = (rule.add_attr != undefined) ? rule.add_attr : false;
        findFieldPosition(d, rule.field_position, rule.selector, false, newAttr, function(data) {
            var field, val, cond_pair = (rule.conditions != null) ? _u.pairs(rule.conditions) : null;

            //Parse over one or more-conditions
            //Note: Better validation if conditions value exists
            if (cond_pair != null && util.isArray(cond_pair)) {
                for (var i = 0; i < cond_pair.length; i++) {
                    field = cond_pair[i][0], val = cond_pair[i][1];
                    if (field != undefined && val != undefined)
                        if ((field == '_' && data[field] != val) || (field != "_" && data['$'][field] != val))
                            return data[rule.selector]; //unchanged value if condition doesn't match
                        else app.log.info('Condition match found for query field: ' + field);
                }
            }

            return rule.set_value; // set new value if passes all conditions, if the field exists in change config file
        });

        process.nextTick(function() {
            utils.updateMDRecord(d, mdrecord);
        });
    }

    // Use config rule (target, selector) to fine node or attribute for edit
    var findFieldPosition = function(data, target, selector, createNewFields, createNewAttr, callback) {
        if (!_u.isObject(target)) {
            if (util.isArray(data[target])) {
                if (createNewFields) {
                    data[target].push(callback(new Object()));
                } else {
                    for (var i = 0; i < data[target].length; i++) findFieldPosition(data[target][i], null, selector, createNewFields, createNewAttr, callback);
                }
            } else if (data[target] != undefined) {
                if (createNewFields)
                    data[target] = callback(new Object(), data[target]);
                else
                    findFieldPosition(data[target], null, selector, createNewFields, createNewAttr, callback);
            } else if (data[selector] != undefined) {
                data[selector] = callback(data);
            } else if (createNewFields && data[target] == undefined) { // No existing field with name exists
                data[target] = callback(new Object());
            } else if (createNewAttr && data[selector] == undefined) {
                data['$'][selector] = callback(data);
            } else {
                app.log.error("Invalid change-rule syntax: Invalid selector: " + target);
            }
        } else {
            _u.each(target, function(val, key, list) {
                if (data[key] != undefined) findFieldPosition(data[key], val, selector, createNewFields, createNewAttr, callback);
                else if (data[selector] != undefined) data[selector] = callback(data);
                else if (createNewFields) data[target] = callback(new Object());
                else if (createNewAttr) data['$'][selector] = callback(data);
                else {
                    app.log.error("Unmatched change-rule config.");
                    app.log.debug("Data: " + util.inspect(data));
                }
            });
        }
    }

    // check Session exists for User(escidoc_handle)?
    utils.getSession(app.schema.models.Session, function(res, err) {
        if (!err) openSession(res, getQuery);
        else throw err;
    });

};
<commit_msg>Fix callback check, empty string can be used.<commit_after>var utils = require('../utils'),
    util = utils.util,
    _u = require('underscore');

var update = module.exports = function(app, queryId, change_json_file) {

    var accepted_change_types = {
        override: "override",
        addition: "addition",
        replace: "replace"
    };

    var Query, Rules, current_rule;

    /** Open and use existing Session for MD-Record(s) submission */
    var openSession = function(session, callback) {
        app.session = session;
        app.log.info("Using existing Session-" + app.session.id);

        return callback(queryId);
    }

    var getQuery = function(queryId) {
        if (queryId.length != 24) throw new Error("Query Id is invalid.");
        app.schema.models.Query.findById(queryId).populate({
            path: '_session',
            select: '_id'
        }).populate("result_collection", null, {
            "status.completed": false
        }).exec(function(err, query) {
            if (err) throw err;
            if (query != null && query._session.id == app.session.id.toString()) {
                Query = query;
                app.log.info("Found query: " + Query.id);
                app.log.info("Applying change-rule(s)...");
                utils.loadJSONFile(change_json_file, function(rules) {
                    if (util.isArray(rules))
                        app.log.debug('One or more rules to apply.');
                    else
                        throw new Error('Illegal change-rule syntax: Should be Array.');

                    Rules = rules; // set global
                    nextRule(); //exec first rule
                });
            } else {
                throw new Error("No Query found for Session: " + app.session.id);
            }
        });
    }

    var nextRule = function() {
        var current_index = (current_rule != null) ? _u.indexOf(Rules, current_rule) : 0;
        if (current_rule != null) current_index++;
        if (current_index < Rules.length) {
            app.log.info("Executing rule (" + current_index + ")...");
            applyChangeRules(Rules[current_index]);
        } else {
            utils.updateQuery(Query, function() {
                process.nextTick(function() {
                    process.exit(0);
                });
            });
        }
    }

    var applyChangeRules = function(rule) {
        current_rule = rule;
        //For each rule apply to query.result_collection
        var results = Query.result_collection;
        for (var i = 0; i < results.length; i++) {
            var mdrecord = results[i];
            if (mdrecord != null) {
                applyChangeRule(mdrecord, rule);
            }
        }

        process.nextTick(nextRule);
    }

    var applyChangeRule = function(mdrecord, rule) {
        switch (rule.change_type) {
            case accepted_change_types.override:
                applyChangeOverride(mdrecord, rule);
                break;
            case accepted_change_types.addition:
                applyChangeAddition(mdrecord, rule);
                break;
            case accepted_change_types.replace:
                applyChangeReplace(mdrecord, rule);
                break;
                //TODO define deletion rule
            default:
                app.log.warn("Illegel change-rule syntax: Change type " + change_type + " unsupported.")
        }
    }

    var applyChangeReplace = function(mdrecord, rule) {
        app.log.info("Applying replace rule...");
        var d = JSON.parse(mdrecord.data); //parse JSON record

        // find node to edit, check against conditions if they exist in config rule and replace with a match condition if exists
        var newAttr = (rule.add_attr != undefined) ? rule.add_attr : false;
        findFieldPosition(d, rule.field_position, rule.selector, false, newAttr, function(data) {
            var field, val, match, cond_pair = (rule.conditions != null) ? _u.pairs(rule.conditions) : null;
            //Parse over one or more-conditions
            //Note: Better validation if conditions value exists
            if (cond_pair != null && util.isArray(cond_pair)) {
                for (var i = 0; i < cond_pair.length; i++) {
                    field = cond_pair[i][0], val = cond_pair[i][1];
                    if (field != undefined && val != undefined)
                        if (field == "$match")
                            match = val;
                        else if ((field == "_" && data[field] != val) || (field != "_" && data["$"][field] != val))
                            return null; //unchanged value if condition doesn't match
                        else app.log.info('Condition match found for query field: ' + field);
                }
            }

            // replace values in data string
            app.log.debug('Replacing str "' + match + '" with "' + rule.set_value + '" on "' + util.inspect(data) + '" + sel:' + rule.selector);
            if (match != null || match != undefined)
                return data[rule.selector].replace(match, rule.set_value);
            else
                return rule.set_value; // set new value with replace() match if passes all conditions, if the field exists in change config file

        });

        process.nextTick(function() {
            utils.updateMDRecord(d, mdrecord);
        });

    }

    var applyChangeAddition = function(mdrecord, rule) {
        app.log.info("Applying addition rule...");

        var d = JSON.parse(mdrecord.data); // parse JSON record

        // Add new field to MD-record
        findFieldPosition(d, rule.field_position, null, true, false, function(data, existingNode) {
            var newNode;
            //app.log.debug('call callback addition:' + util.inspect(existingNode));
            if (existingNode != null) {
                newNode = new Array(2);
                newNode[0] = existingNode;
                newNode[1] = _u.extend(data, rule.properties);
            } else {
                newNode = _u.extend(data, rule.properties);
            }

            return newNode;
        });

        process.nextTick(function() {
            utils.updateMDRecord(d, mdrecord);
        });
    }

    var applyChangeOverride = function(mdrecord, rule) {
        app.log.info("Applying override rule...");

        var d = JSON.parse(mdrecord.data); // parse JSON record

        // find node to edit, check against conditions if they exist in config rules
        var newAttr = (rule.add_attr != undefined) ? rule.add_attr : false;

        findFieldPosition(d, rule.field_position, rule.selector, false, newAttr, function(data) {
            var field, val, cond_pair = (rule.conditions != null) ? _u.pairs(rule.conditions) : null;

            //Parse over one or more-conditions
            //Note: Better validation if conditions value exists
            if (cond_pair != null && util.isArray(cond_pair)) {
                for (var i = 0; i < cond_pair.length; i++) {
                    field = cond_pair[i][0], val = cond_pair[i][1];
                    if (field != undefined && val != undefined) {
                        if ((field === "_" && data[field] != val) || (field != "_" && data['$'][field] != val)) {
                             app.log.warn('Conditional match not found on selected field: ' + field + ' ' + val);
                             return null; //unchanged value if condition doesn't match
                        } else app.log.info('Conditional match found on selected field: ' + field);
                    }
                }
            }

            return rule.set_value; // set new value if passes all conditions, if the field exists in change config file
        });

        process.nextTick(function() {
            utils.updateMDRecord(d, mdrecord);
        });
    }

    // Use config rule (target, selector) to fine node or attribute for edit
    var findFieldPosition = function(data, target, selector, createNewFields, createNewAttr, callback) {
        if (!_u.isObject(target)) {
            if (util.isArray(data[target])) {
                if (createNewFields) {
                    data[target].push(callback(new Object()));
                } else {
                    for (var i = 0; i < data[target].length; i++) {
                      app.log.warn('Testing array position [' + i + '] on ' + target);
                      findFieldPosition(data[target][i], null, selector, createNewFields, createNewAttr, callback);
                    }
                }
            } else if (target != null && data[target] != undefined) {
                if (createNewFields)
                    data[target] = callback(new Object(), data[target]);
                else
                    findFieldPosition(data[target], null, selector, createNewFields, createNewAttr, callback);
            } else {
              var cb = callback(data);
              if (cb != null) { // TODO: test against callback function
                if (data[selector] != undefined) {
                  data[selector] = cb;
                } else if ((data['$'][selector] != undefined) || (createNewAttr && data['$'][selector] == undefined)) {
                    data['$'][selector] = cb;
                } else if (selector != null) {
                    app.log.error("Invalid change-rule syntax: Invalid selector: " + selector);
                }

                if (createNewFields && data[target] == undefined) { // No existing field with name exists
                    data[target] = cb;
                } else if (target != null) {
                    app.log.error("Invalid change-rule syntax: Invalid target: " + target);
                }
              }
            }
        } else {
            _u.each(target, function(val, key, list) {
                if (data[key] != undefined) findFieldPosition(data[key], val, selector, createNewFields, createNewAttr, callback);
                else if (data[selector] != undefined) data[selector] = callback(data);
                else if (data['$'][selector] != undefined) data['$'][selector] = callback(data);
                else if (createNewFields) data[target] = callback(new Object());
                else if (createNewAttr) data['$'][selector] = callback(data);
                else {
                    app.log.error("Unmatched change-rule config.");
                    app.log.debug("Data: " + util.inspect(data));
                }
            });
        }
    }

    // check Session exists for User(escidoc_handle)?
    utils.getSession(app.schema.models.Session, function(res, err) {
        if (!err) openSession(res, getQuery);
        else throw err;
    });

};
<|endoftext|>


<commit_before>/*globals module,require*/
module.exports = (function() {
  var spawn = require('child_process').spawn
  var proc, currentTrack, to_recent, currentTrackData = [] //To store id and url of current track
    ,
    queue = [],
    recent = [] // to store recent played songs
    ,
    playing = 0,
    now = 0;
  var youtubeData = {};
  var play = function(url, id) {
    if (!playing) {
      currentTrackData[0] = url;
      currentTrackData[1] = id;
      playing = 1;
      now = playing;
      // youtube link
      // because, otherwise it will add 'youtube' in the '/list' or '/recent' or '/current' :|
      if (id == 'youtube') {
        if (url.indexOf('?v=') != -1 || url.indexOf('&v=') != -1) {
          var yid = parseYoutubeId(url);
          if (typeof(proc) !== 'undefined') {
            proc.kill();
          }

          // Spawning link to the track
          var child = spawn("youtube-dl", ["-g", url]);
          var link = "";
          child.stdout.on('data', function(data) {
            link = link + data;
          });
          child.stderr.on('data', function(data) {
            console.log('youtube-dl stderr: ' + data);
          });
          child.on('close', function(code) {
            var links = link.split('\n');
            var first_link = links[0];

            if (!youtubeData[yid])
              setYoutubeInfo(url);

            proc = spawn("vlc", ["-Incurse", "--play-and-exit", first_link]);
            proc.on('exit', queuefunc);
          });
          currentTrack = [yid];
          to_recent = yid;
        }
      }
      // muzi link
      else {
        currentTrack = [id];
        to_recent = id;

        proc = spawn("vlc", ["-Incurse", "--play-and-exit", url]);
        proc.on('exit', queuefunc);
      }
    } else {
      var entry = [];
      entry[0] = url;
      entry[1] = id;
      queue.push(entry);
      if (id == 'youtube') {
        if (url.indexOf('?v=') != -1 || url.indexOf('&v=') != -1) {
          if (!youtubeData[parseYoutubeId(url)])
            setYoutubeInfo(url);
        }
      }
    }
  }

  var repeatCurrent = function() {
    if (currentTrackData.length > 0) {
      queue.unshift(currentTrackData);
      currentTrackData = [];
      return true;
    } else {
      return false;
    }
  }

  var kill = function() {
    proc.kill();
  }

  var getNext = function() {
    if (queue.length > 0) {
      return [queue[0][1]];
    } else
      return null;
  }

  var parseYoutubeId = function(url) {
    var key = '';
    if (url.indexOf('?v=') != -1) {
      a = url.indexOf('?v=');
      for (var i = a + 3; i < a + 14; i++) {
        key = key + url[i];
      }
    } else if (url.indexOf('&v=') != -1) {
      a = url.indexOf('&v=');
      for (var i = a + 3; i < a + 14; i++) {
        key = key + url[i];
      }
    }
    return key;
  }

  var setYoutubeInfo = function(url) {
    var info = "";
    var child = spawn("youtube-dl", ["-j", url]);
    child.stdout.on('data', function(data) {
      info = info + data;
    })
    child.on('close', function() {
      info = JSON.parse(info);
      yid = info.id;
      youtubeData[yid] = {
        'data': {
          'title': info.title,
          'uploader': info.uploader,
          'thumbnail': info.thumbnail
        }
      };
    })
  }

  var queuefunc = function() {
    console.log('Queuing...');
    playing = 0;
    now = playing;
    // for recent
    x = [];
    x.push(to_recent);
    l = recent.length;
    // showing recent 5 songs only
    if (l > 0) {
      if (l >= 5) {
        for (var a = 0; a < 4; a++) {
          x.push(recent[a]);
        }
      } else {
        for (var a = 0; a < l; a++) {
          x.push(recent[a]);
        }
      }
    }
    recent = x;
    //
    if (typeof queue[0] !== 'undefined') {
      play(queue[0][0], queue[0][1]);
      queue.shift();
    }
  }

  var queuelist = function() {
    return queue;
  }

  var recentlist = function() {
    return recent;
  }

  var _getCurrent = function() {
    return currentTrack;
  }
  var rightnow = function() {
    return now;
  }

  var getYoutubeInfo = function(id) {
    return youtubeData[id];
  }

  return {
    play: play,
    getCurrent: _getCurrent,
    queuelist: queuelist,
    kill: kill,
    recentlist: recentlist,
    rightnow: rightnow,
    repeatCurrent: repeatCurrent,
    getNext: getNext,
    getYoutubeInfo: getYoutubeInfo
  }
})();<commit_msg>Update vlc player command<commit_after>/*globals module,require*/
module.exports = (function() {
  var spawn = require('child_process').spawn
  var proc, currentTrack, to_recent, currentTrackData = [] //To store id and url of current track
    ,
    queue = [],
    recent = [] // to store recent played songs
    ,
    playing = 0,
    now = 0;
  var youtubeData = {};
  var play = function(url, id) {
    if (!playing) {
      currentTrackData[0] = url;
      currentTrackData[1] = id;
      playing = 1;
      now = playing;
      // youtube link
      // because, otherwise it will add 'youtube' in the '/list' or '/recent' or '/current' :|
      if (id == 'youtube') {
        if (url.indexOf('?v=') != -1 || url.indexOf('&v=') != -1) {
          var yid = parseYoutubeId(url);
          if (typeof(proc) !== 'undefined') {
            proc.kill();
          }

          // Spawning link to the track
          var child = spawn("youtube-dl", ["-g", url]);
          var link = "";
          child.stdout.on('data', function(data) {
            link = link + data;
          });
          child.stderr.on('data', function(data) {
            console.log('youtube-dl stderr: ' + data);
          });
          child.on('close', function(code) {
            var links = link.split('\n');
            var first_link = links[0];

            if (!youtubeData[yid])
              setYoutubeInfo(url);

            proc = spawn("vlc", ["-Incurse", "--vout", "none", "--play-and-exit", first_link]);
            proc.on('exit', queuefunc);
          });
          currentTrack = [yid];
          to_recent = yid;
        }
      }
      // muzi link
      else {
        currentTrack = [id];
        to_recent = id;

        proc = spawn("vlc", ["-Incurse", "--vout", "none", "--play-and-exit", url]);
        proc.on('exit', queuefunc);
      }
    } else {
      var entry = [];
      entry[0] = url;
      entry[1] = id;
      queue.push(entry);
      if (id == 'youtube') {
        if (url.indexOf('?v=') != -1 || url.indexOf('&v=') != -1) {
          if (!youtubeData[parseYoutubeId(url)])
            setYoutubeInfo(url);
        }
      }
    }
  }

  var repeatCurrent = function() {
    if (currentTrackData.length > 0) {
      queue.unshift(currentTrackData);
      currentTrackData = [];
      return true;
    } else {
      return false;
    }
  }

  var kill = function() {
    proc.kill();
  }

  var getNext = function() {
    if (queue.length > 0) {
      return [queue[0][1]];
    } else
      return null;
  }

  var parseYoutubeId = function(url) {
    var key = '';
    if (url.indexOf('?v=') != -1) {
      a = url.indexOf('?v=');
      for (var i = a + 3; i < a + 14; i++) {
        key = key + url[i];
      }
    } else if (url.indexOf('&v=') != -1) {
      a = url.indexOf('&v=');
      for (var i = a + 3; i < a + 14; i++) {
        key = key + url[i];
      }
    }
    return key;
  }

  var setYoutubeInfo = function(url) {
    var info = "";
    var child = spawn("youtube-dl", ["-j", url]);
    child.stdout.on('data', function(data) {
      info = info + data;
    })
    child.on('close', function() {
      info = JSON.parse(info);
      yid = info.id;
      youtubeData[yid] = {
        'data': {
          'title': info.title,
          'uploader': info.uploader,
          'thumbnail': info.thumbnail
        }
      };
    })
  }

  var queuefunc = function() {
    console.log('Queuing...');
    playing = 0;
    now = playing;
    // for recent
    x = [];
    x.push(to_recent);
    l = recent.length;
    // showing recent 5 songs only
    if (l > 0) {
      if (l >= 5) {
        for (var a = 0; a < 4; a++) {
          x.push(recent[a]);
        }
      } else {
        for (var a = 0; a < l; a++) {
          x.push(recent[a]);
        }
      }
    }
    recent = x;
    //
    if (typeof queue[0] !== 'undefined') {
      play(queue[0][0], queue[0][1]);
      queue.shift();
    }
  }

  var queuelist = function() {
    return queue;
  }

  var recentlist = function() {
    return recent;
  }

  var _getCurrent = function() {
    return currentTrack;
  }
  var rightnow = function() {
    return now;
  }

  var getYoutubeInfo = function(id) {
    return youtubeData[id];
  }

  return {
    play: play,
    getCurrent: _getCurrent,
    queuelist: queuelist,
    kill: kill,
    recentlist: recentlist,
    rightnow: rightnow,
    repeatCurrent: repeatCurrent,
    getNext: getNext,
    getYoutubeInfo: getYoutubeInfo
  }
})();<|endoftext|>


<commit_before>/**
 * @constructor
 * @param {number} id
 * @param {EditSession} session Edit session.
 * @param {FileEntry} entry
 */
function Tab(id, session, entry, dialogController) {
  this.id_ = id;
  this.session_ = session;
  this.entry_ = entry;
  this.saved_ = true;
  this.path_ = null;
  this.dialogController_ = dialogController;
  if (this.entry_)
    this.updatePath_();
};

Tab.prototype.getId = function() {
  return this.id_;
};

Tab.prototype.getName = function() {
  if (this.entry_) {
    return this.entry_.name;
  } else {
    return 'Untitled ' + this.id_;
  }
};

/**
 * @return {string?} Filename extension or null.
 */
Tab.prototype.getExtension = function() {
  if (!this.entry_)
    return null;

  var match = /\.([^.\\\/]+)$/.exec(this.getName());

  if (match) {
    return match[1];
  } else {
    return null;
  }
};

Tab.prototype.getSession = function() {
  return this.session_;
};

/**
 * @param {FileEntry} entry
 */
Tab.prototype.setEntry = function(entry) {
  var nameChanged = this.getName() != entry.name;
  this.entry_ = entry;
  if (nameChanged)
    $.event.trigger('tabrenamed', this);
  this.updatePath_();
};

Tab.prototype.getEntry = function() {
  return this.entry_;
};

Tab.prototype.getPath = function() {
  return this.path_;
};

Tab.prototype.updatePath_ = function() {
  chrome.fileSystem.getDisplayPath(this.entry_, function(path) {
    this.path_ = path;
  }.bind(this));
};

Tab.prototype.save = function(opt_callbackDone) {
  util.writeFile(
      this.entry_, this.session_.getValue(),
      function() {
        this.saved_ = true;
        $.event.trigger('tabsave', this);
        if (opt_callbackDone)
          opt_callbackDone();
      }.bind(this),
      this.reportWriteError_.bind(this));
};

Tab.prototype.reportWriteError_ = function(e) {
  this.dialogController_.setText(
      'Error saving file: ' + util.fsErrorStr(e));
  this.dialogController_.resetButtons();
  this.dialogController_.addButton('ok', 'OK');
  this.dialogController_.show();
};

Tab.prototype.isSaved = function() {
  return this.saved_;
};

Tab.prototype.changed = function() {
  if (this.saved_) {
    this.saved_ = false;
    $.event.trigger('tabchange', this);
  }
};

/**
 * @constructor
 */
function Tabs(editor, dialogController, settings) {
  this.editor_ = editor;
  this.dialogController_ = dialogController;
  this.settings_ = settings;
  this.tabs_ = [];
  this.currentTab_ = null;
  $(document).bind('docchange', this.onDocChanged_.bind(this));
}

/**
 * @type {Object} params
 * @type {function(FileEntry)} callback
 * @type {function()} opt_oncancel
 * Open a file in the system file picker. The FileEntry is copied to be stored
 * in background page, so it isn't destroyed when the window is closed.
 */
Tabs.prototype.chooseEntry = function(params, callback, opt_oncancel) {
  // TODO: Add `params.acceptsMultiple = false` when crbug.com/326523 is fixed.
  chrome.fileSystem.chooseEntry(
      params,
      function(entry) {
        if (entry) {
          chrome.runtime.getBackgroundPage(function(bg) {
            bg.background.copyFileEntry(entry, callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

/**
 * @type {Object} params
 * @type {function(Array.<FileEntry>)} callback
 * @type {function()} opt_oncancel
 * Open one or multiple files in the system file picker. File Entries are
 * copied to be stored in background page, so it isn't destroyed when the
 * window is closed.
 */
Tabs.prototype.chooseEntries = function(params, callback, opt_oncancel) {
  params.acceptsMultiple = true;
  chrome.fileSystem.chooseEntry(
      params,
      function(entries) {
        if (entries) {
          chrome.runtime.getBackgroundPage(function(bg) {
            for (var i = 0; i < entries.length; i++)
              bg.background.copyFileEntry(entries[i], callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

Tabs.prototype.getTabById = function(id) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() === id)
      return this.tabs_[i];
  }
  return null;
};

Tabs.prototype.getCurrentTab = function(id) {
  return this.currentTab_;
};

Tabs.prototype.newWindow = function() {
  chrome.runtime.getBackgroundPage(function(bg) {
    bg.background.newWindow();
  }.bind(this));
};

Tabs.prototype.newTab = function(opt_content, opt_entry) {
  var id = 1;
  while (this.getTabById(id)) {
    id++;
  }

  var session = this.editor_.newSession(opt_content);

  var tab = new Tab(id, session, opt_entry || null, this.dialogController_);
  this.tabs_.push(tab);
  $.event.trigger('newtab', tab);
  this.showTab(tab.getId());
  var fileNameExtension = tab.getExtension();
  if (fileNameExtension)
    this.editor_.setMode(session, fileNameExtension);
};

Tabs.prototype.nextTab = function() {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === this.currentTab_) {
      var next = i + 1;
      if (next === this.tabs_.length)
        next = 0;
      if (next !== i)
        this.showTab(this.tabs_[next].getId());
      return;
    }
  }
};

Tabs.prototype.showTab = function(tabId) {
  var tab = this.getTabById(tabId)
  this.editor_.setSession(tab.getSession());
  this.currentTab_ = tab;
  $.event.trigger('switchtab', tab);
  this.editor_.focus();
};

Tabs.prototype.close = function(tabId) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() == tabId)
      break;
  }

  if (i >= this.tabs_.length) {
    console.error('Can\'t find tab', tabId);
    return;
  }

  var tab = this.tabs_[i];

  if (!tab.isSaved()) {
    if (this.settings_.get('autosave') && tab.getEntry()) {
      this.save(tab, true /* close */);
    } else {
      this.dialogController_.setText(
          'Do you want to save the file before closing?');
      this.dialogController_.resetButtons();
      this.dialogController_.addButton('yes', 'Yes');
      this.dialogController_.addButton('no', 'No');
      this.dialogController_.addButton('cancel', 'Cancel');
      this.dialogController_.show(function(answer) {
        if (answer === 'yes') {
          this.save(tab, true /* close */);
          return;
        }

        if (answer === 'no') {
          this.closeTab_(tab);
          return;
        }
      }.bind(this));
    }
  } else {
    this.closeTab_(tab);
  }
};

/**
 * @param {Tab} tab
 * Close tab without checking whether it needs to be saved. The safe version
 * (invoking auto-save and, if needed, SaveAs dialog) is Tabs.close().
 */
Tabs.prototype.closeTab_ = function(tab) {
  if (tab === this.currentTab_) {
    if (this.tabs_.length > 1) {
      this.nextTab();
    } else {
      window.close();
    }
  }

  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === tab)
      break;
  }

  this.tabs_.splice(i, 1);
  $.event.trigger('tabclosed', tab);
};

Tabs.prototype.closeCurrent = function() {
  this.close(this.currentTab_.getId());
};

Tabs.prototype.openFiles = function() {
  this.chooseEntries(
      {'type': 'openWritableFile'},
      this.openFileEntry.bind(this));
};

Tabs.prototype.save = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  if (opt_tab.getEntry()) {
    var callback = null;
    if (opt_close)
      callback = this.closeTab_.bind(this, opt_tab);
    opt_tab.save(callback);
  } else {
    this.saveAs(opt_tab, opt_close);
  }
};

Tabs.prototype.saveAs = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  this.chooseEntry(
      {'type': 'saveFile'},
      this.onSaveAsFileOpen_.bind(this, opt_tab, opt_close || false));
};

/**
 * @return {Array.<Object>} Each element:
 *     {entry: <FileEntry>, contents: <string>}.
 */
Tabs.prototype.getFilesToSave = function() {
  var toSave = [];

  for (i = 0; i < this.tabs_.length; i++) {
    if (!this.tabs_[i].isSaved() && this.tabs_[i].getEntry()) {
      toSave.push({'entry': this.tabs_[i].getEntry(),
                   'contents': editor.getContents(this.tabs_[i].getSession())});
    }
  }

  return toSave;
};

Tabs.prototype.openFileEntry = function(entry) {
  chrome.fileSystem.getDisplayPath(entry, function(path) {
    for (var i = 0; i < this.tabs_.length; i++) {
      if (this.tabs_[i].getPath() === path) {
        this.showTab(this.tabs_[i].getId());
        return;
      }
    }

    entry.file(this.readFileToNewTab_.bind(this, entry));
  }.bind(this));
};

Tabs.prototype.modeAutoSet = function(tab) {
  var extension = tab.getExtension();
  if (extension) {
    this.editor_.setMode(tab.getSession(), extension);
  }
};

Tabs.prototype.readFileToNewTab_ = function(entry, file) {
  var self = this;
  var reader = new FileReader();
  reader.onerror = util.handleFSError;
  reader.onloadend = function(e) {
    self.newTab(this.result, entry);
    if (self.tabs_.length === 2 &&
        !self.tabs_[0].getEntry() &&
        self.tabs_[0].isSaved()) {
      self.close(self.tabs_[0].getId());
    }
  };
  reader.readAsText(file);
}

Tabs.prototype.onSaveAsFileOpen_ = function(tab, close, entry) {
  if (!entry) {
    return;
  }

  tab.setEntry(entry);
  this.save(tab, close);
};

Tabs.prototype.onDocChanged_ = function(e, session) {
  var tab = this.currentTab_;
  if (this.currentTab_.getSession() !== session) {
    console.warn('Something wrong. Current session should be',
                 this.currentTab_.getSession(),
                 ', but this session was changed:', session);
    for (var i = 0; i < this.tabs_; i++) {
      if (this.tabs_[i].getSession() === session) {
        tab = this.tabs_[i];
        break;
      }
    }

    if (tab === this.currentTab_) {
      console.error('Unkown tab changed.');
      return;
    }
  }

  tab.changed();
};
<commit_msg>Changed the way acceptsMultiple is handled on save<commit_after>/**
 * @constructor
 * @param {number} id
 * @param {EditSession} session Edit session.
 * @param {FileEntry} entry
 */
function Tab(id, session, entry, dialogController) {
  this.id_ = id;
  this.session_ = session;
  this.entry_ = entry;
  this.saved_ = true;
  this.path_ = null;
  this.dialogController_ = dialogController;
  if (this.entry_)
    this.updatePath_();
};

Tab.prototype.getId = function() {
  return this.id_;
};

Tab.prototype.getName = function() {
  if (this.entry_) {
    return this.entry_.name;
  } else {
    return 'Untitled ' + this.id_;
  }
};

/**
 * @return {string?} Filename extension or null.
 */
Tab.prototype.getExtension = function() {
  if (!this.entry_)
    return null;

  var match = /\.([^.\\\/]+)$/.exec(this.getName());

  if (match) {
    return match[1];
  } else {
    return null;
  }
};

Tab.prototype.getSession = function() {
  return this.session_;
};

/**
 * @param {FileEntry} entry
 */
Tab.prototype.setEntry = function(entry) {
  var nameChanged = this.getName() != entry.name;
  this.entry_ = entry;
  if (nameChanged)
    $.event.trigger('tabrenamed', this);
  this.updatePath_();
};

Tab.prototype.getEntry = function() {
  return this.entry_;
};

Tab.prototype.getPath = function() {
  return this.path_;
};

Tab.prototype.updatePath_ = function() {
  chrome.fileSystem.getDisplayPath(this.entry_, function(path) {
    this.path_ = path;
  }.bind(this));
};

Tab.prototype.save = function(opt_callbackDone) {
  util.writeFile(
      this.entry_, this.session_.getValue(),
      function() {
        this.saved_ = true;
        $.event.trigger('tabsave', this);
        if (opt_callbackDone)
          opt_callbackDone();
      }.bind(this),
      this.reportWriteError_.bind(this));
};

Tab.prototype.reportWriteError_ = function(e) {
  this.dialogController_.setText(
      'Error saving file: ' + util.fsErrorStr(e));
  this.dialogController_.resetButtons();
  this.dialogController_.addButton('ok', 'OK');
  this.dialogController_.show();
};

Tab.prototype.isSaved = function() {
  return this.saved_;
};

Tab.prototype.changed = function() {
  if (this.saved_) {
    this.saved_ = false;
    $.event.trigger('tabchange', this);
  }
};

/**
 * @constructor
 */
function Tabs(editor, dialogController, settings) {
  this.editor_ = editor;
  this.dialogController_ = dialogController;
  this.settings_ = settings;
  this.tabs_ = [];
  this.currentTab_ = null;
  $(document).bind('docchange', this.onDocChanged_.bind(this));
}

/**
 * @type {Object} params
 * @type {function(FileEntry)} callback
 * @type {function()} opt_oncancel
 * Open a file in the system file picker. The FileEntry is copied to be stored
 * in background page, so it isn't destroyed when the window is closed.
 */
Tabs.prototype.chooseEntry = function(params, callback, opt_oncancel) {
  // TODO: Remove this when crbug.com/326523 is fixed.
  if (params.acceptsMultiple) {
    console.error('acceptsMultiple is not supported when saving a file');
    return;
  }
  chrome.fileSystem.chooseEntry(
      params,
      function(entry) {
        if (entry) {
          chrome.runtime.getBackgroundPage(function(bg) {
            bg.background.copyFileEntry(entry, callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

/**
 * @type {Object} params
 * @type {function(Array.<FileEntry>)} callback
 * @type {function()} opt_oncancel
 * Open one or multiple files in the system file picker. File Entries are
 * copied to be stored in background page, so they aren't destroyed when the
 * window is closed. Callback is called once for each File Entry.
 */
Tabs.prototype.chooseEntries = function(params, callback, opt_oncancel) {
  params.acceptsMultiple = true;
  chrome.fileSystem.chooseEntry(
      params,
      function(entries) {
        if (entries) {
          chrome.runtime.getBackgroundPage(function(bg) {
            for (var i = 0; i < entries.length; i++)
              bg.background.copyFileEntry(entries[i], callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

Tabs.prototype.getTabById = function(id) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() === id)
      return this.tabs_[i];
  }
  return null;
};

Tabs.prototype.getCurrentTab = function(id) {
  return this.currentTab_;
};

Tabs.prototype.newWindow = function() {
  chrome.runtime.getBackgroundPage(function(bg) {
    bg.background.newWindow();
  }.bind(this));
};

Tabs.prototype.newTab = function(opt_content, opt_entry) {
  var id = 1;
  while (this.getTabById(id)) {
    id++;
  }

  var session = this.editor_.newSession(opt_content);

  var tab = new Tab(id, session, opt_entry || null, this.dialogController_);
  this.tabs_.push(tab);
  $.event.trigger('newtab', tab);
  this.showTab(tab.getId());
  var fileNameExtension = tab.getExtension();
  if (fileNameExtension)
    this.editor_.setMode(session, fileNameExtension);
};

Tabs.prototype.nextTab = function() {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === this.currentTab_) {
      var next = i + 1;
      if (next === this.tabs_.length)
        next = 0;
      if (next !== i)
        this.showTab(this.tabs_[next].getId());
      return;
    }
  }
};

Tabs.prototype.showTab = function(tabId) {
  var tab = this.getTabById(tabId)
  this.editor_.setSession(tab.getSession());
  this.currentTab_ = tab;
  $.event.trigger('switchtab', tab);
  this.editor_.focus();
};

Tabs.prototype.close = function(tabId) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() == tabId)
      break;
  }

  if (i >= this.tabs_.length) {
    console.error('Can\'t find tab', tabId);
    return;
  }

  var tab = this.tabs_[i];

  if (!tab.isSaved()) {
    if (this.settings_.get('autosave') && tab.getEntry()) {
      this.save(tab, true /* close */);
    } else {
      this.dialogController_.setText(
          'Do you want to save the file before closing?');
      this.dialogController_.resetButtons();
      this.dialogController_.addButton('yes', 'Yes');
      this.dialogController_.addButton('no', 'No');
      this.dialogController_.addButton('cancel', 'Cancel');
      this.dialogController_.show(function(answer) {
        if (answer === 'yes') {
          this.save(tab, true /* close */);
          return;
        }

        if (answer === 'no') {
          this.closeTab_(tab);
          return;
        }
      }.bind(this));
    }
  } else {
    this.closeTab_(tab);
  }
};

/**
 * @param {Tab} tab
 * Close tab without checking whether it needs to be saved. The safe version
 * (invoking auto-save and, if needed, SaveAs dialog) is Tabs.close().
 */
Tabs.prototype.closeTab_ = function(tab) {
  if (tab === this.currentTab_) {
    if (this.tabs_.length > 1) {
      this.nextTab();
    } else {
      window.close();
    }
  }

  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === tab)
      break;
  }

  this.tabs_.splice(i, 1);
  $.event.trigger('tabclosed', tab);
};

Tabs.prototype.closeCurrent = function() {
  this.close(this.currentTab_.getId());
};

Tabs.prototype.openFiles = function() {
  this.chooseEntries(
      {'type': 'openWritableFile'},
      this.openFileEntry.bind(this));
};

Tabs.prototype.save = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  if (opt_tab.getEntry()) {
    var callback = null;
    if (opt_close)
      callback = this.closeTab_.bind(this, opt_tab);
    opt_tab.save(callback);
  } else {
    this.saveAs(opt_tab, opt_close);
  }
};

Tabs.prototype.saveAs = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  this.chooseEntry(
      {'type': 'saveFile'},
      this.onSaveAsFileOpen_.bind(this, opt_tab, opt_close || false));
};

/**
 * @return {Array.<Object>} Each element:
 *     {entry: <FileEntry>, contents: <string>}.
 */
Tabs.prototype.getFilesToSave = function() {
  var toSave = [];

  for (i = 0; i < this.tabs_.length; i++) {
    if (!this.tabs_[i].isSaved() && this.tabs_[i].getEntry()) {
      toSave.push({'entry': this.tabs_[i].getEntry(),
                   'contents': editor.getContents(this.tabs_[i].getSession())});
    }
  }

  return toSave;
};

Tabs.prototype.openFileEntry = function(entry) {
  chrome.fileSystem.getDisplayPath(entry, function(path) {
    for (var i = 0; i < this.tabs_.length; i++) {
      if (this.tabs_[i].getPath() === path) {
        this.showTab(this.tabs_[i].getId());
        return;
      }
    }

    entry.file(this.readFileToNewTab_.bind(this, entry));
  }.bind(this));
};

Tabs.prototype.modeAutoSet = function(tab) {
  var extension = tab.getExtension();
  if (extension) {
    this.editor_.setMode(tab.getSession(), extension);
  }
};

Tabs.prototype.readFileToNewTab_ = function(entry, file) {
  var self = this;
  var reader = new FileReader();
  reader.onerror = util.handleFSError;
  reader.onloadend = function(e) {
    self.newTab(this.result, entry);
    if (self.tabs_.length === 2 &&
        !self.tabs_[0].getEntry() &&
        self.tabs_[0].isSaved()) {
      self.close(self.tabs_[0].getId());
    }
  };
  reader.readAsText(file);
}

Tabs.prototype.onSaveAsFileOpen_ = function(tab, close, entry) {
  if (!entry) {
    return;
  }

  tab.setEntry(entry);
  this.save(tab, close);
};

Tabs.prototype.onDocChanged_ = function(e, session) {
  var tab = this.currentTab_;
  if (this.currentTab_.getSession() !== session) {
    console.warn('Something wrong. Current session should be',
                 this.currentTab_.getSession(),
                 ', but this session was changed:', session);
    for (var i = 0; i < this.tabs_; i++) {
      if (this.tabs_[i].getSession() === session) {
        tab = this.tabs_[i];
        break;
      }
    }

    if (tab === this.currentTab_) {
      console.error('Unkown tab changed.');
      return;
    }
  }

  tab.changed();
};
<|endoftext|>