<commit_before>//
//  Created by Mingliang Chen on 17/8/4.
//  illuspas[a]gmail.com
//  Copyright (c) 2017 Nodemedia. All rights reserved.
//
const EventEmitter = require('events');
const URL = require('url');

const AMF = require('./node_core_amf');
const BufferPool = require('./node_core_bufferpool');
const NodeCoreUtils = require('./node_core_utils');

class NodeFlvSession extends EventEmitter {
  constructor(config, req, res) {
    super();
    this.config = config;
    this.req = req;
    this.res = res;
    this.bp = new BufferPool(this.handleData());
    this.bp.on('error', (e) => {

    });
    this.allow_origin = config.http.allow_origin == undefined ? '*' : config.http.allow_origin;
    this.isPublisher = false;
    this.playStreamPath = '';
    this.playArgs = null;
    this.nodeEvent = NodeCoreUtils.nodeEvent;

    this.on('connect', this.onConnect);
    this.on('play', this.onPlay);
    this.on('publish', this.onPublish);

    if (req.nmsConnectionType === 'ws') {
      this.res.on('message', this.onReqData.bind(this));
      this.res.on('close', this.onReqClose.bind(this));
      this.res.on('error', this.onReqError.bind(this));
      this.res.write = this.res.send;
      this.res.end = this.res.close;
      this.TAG = 'websocket-flv'
    } else {
      this.req.on('data', this.onReqData.bind(this));
      this.req.socket.on('close', this.onReqClose.bind(this));
      this.req.on('error', this.onReqError.bind(this));
      this.TAG = 'http-flv'
    }

  }

  run() {
    let method = this.req.method;
    let urlInfo = URL.parse(this.req.url, true);
    let streamPath = urlInfo.pathname.split('.')[0];
    let format = urlInfo.pathname.split('.')[1];
    this.connectCmdObj = { method, streamPath, query: urlInfo.query };
    this.nodeEvent.emit('preConnect', this.id, this.connectCmdObj);

    this.isStarting = true;
    this.bp.init();

    this.connectTime = new Date();

    if (format != 'flv') {
      console.log(`[${this.TAG}] Unsupported format=${format}`);
      this.res.statusCode = 403;
      this.res.end();
      return;
    }
    this.nodeEvent.emit('postConnect', this.id, this.connectCmdObj);
    if (method == 'GET') {
      //Play
      this.playStreamPath = streamPath;
      this.playArgs = urlInfo.query;
      console.log(`[${this.TAG} play] play stream ` + this.playStreamPath);
      this.emit('play');

    } else if (method == 'POST') {
      //Publish

      console.log(`[${this.TAG}] Unsupported method=` + method);
      this.res.statusCode = 405;
      this.res.end();
      return;
    } else {
      console.log(`[${this.TAG}] Unsupported method=` + method);
      this.res.statusCode = 405;
      this.res.end();
      return;
    }
  }

  onReqData(data) {
    this.bp.push(data);
  }

  onReqClose() {
    this.stop();
  }

  onReqError(e) {
    this.stop();
  }

  stop() {
    if (this.isStarting) {
      this.isStarting = false;
      this.bp.stop();
    }
  }

  reject() {
    this.stop();
  }

  * handleData() {

    console.log(`[${this.TAG} message parser] start`);
    while (this.isStarting) {
      if (this.bp.need(9)) {
        if (yield) break;
      }
    }

    console.log(`[${this.TAG} message parser] done`);
    if (this.isPublisher) {

    } else {
      let publisherId = this.publishers.get(this.playStreamPath);
      if (publisherId != null) {
        this.sessions.get(publisherId).players.delete(this.id);
        this.nodeEvent.emit('donePlay', this.id, this.playStreamPath, this.playArgs);
      }
    }
    this.nodeEvent.emit('doneConnect', this.id, this.connectCmdObj);
    this.res.end();
    this.idlePlayers.delete(this.id);
    this.sessions.delete(this.id);
    this.idlePlayers = null;
    this.publishers = null;
    this.sessions = null;
  }

  respondUnpublish() {
    this.res.end();
  }

  onConnect() {

  }

  onPlay() {

    this.nodeEvent.emit('prePlay', this.id, this.playStreamPath, this.playArgs);
    if (!this.isStarting) {
      return;
    }
    if (this.config.auth !== undefined && this.config.auth.play) {
      let results = NodeCoreUtils.verifyAuth(this.playArgs.sign, this.playStreamPath, this.config.auth.secret);
      if (!results) {
        console.log(`[${this.TAG}] Unauthorized. ID=${this.id} streamPath=${this.playStreamPath} sign=${this.playArgs.sign}`);
        this.res.statusCode = 401;
        this.res.end();
        return;
      }
    }

    if (!this.publishers.has(this.playStreamPath)) {
      console.log(`[${this.TAG} play] stream not found ` + this.playStreamPath);
      this.idlePlayers.add(this.id);
      return;
    }

    let publisherId = this.publishers.get(this.playStreamPath);
    let publisher = this.sessions.get(publisherId);
    let players = publisher.players;
    players.add(this.id);

    if (this.res.setHeader !== undefined) {
      this.res.setHeader('Content-Type', 'video/x-flv');
      this.res.setHeader('Access-Control-Allow-Origin', this.allow_origin);
    }

    //send FLV header
    let FLVHeader = Buffer.from([0x46, 0x4C, 0x56, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00]);
    if (publisher.isFirstAudioReceived) {
      FLVHeader[4] |= 0b00000100;
    }

    if (publisher.isFirstVideoReceived) {
      FLVHeader[4] |= 0b00000001;
    }
    this.res.write(FLVHeader);
    if (publisher.metaData != null) {
      //send Metadata
      let rtmpHeader = {
        chunkStreamID: 5,
        timestamp: 0,
        messageTypeID: 0x12,
        messageStreamID: 1
      };

      let metaDataFlvMessage = NodeFlvSession.createFlvMessage(rtmpHeader, publisher.metaData);
      this.res.write(metaDataFlvMessage);
    }
    //send aacSequenceHeader
    if (publisher.audioCodec == 10) {
      let rtmpHeader = {
        chunkStreamID: 4,
        timestamp: 0,
        messageTypeID: 0x08,
        messageStreamID: 1
      };
      let flvMessage = NodeFlvSession.createFlvMessage(rtmpHeader, publisher.aacSequenceHeader);
      this.res.write(flvMessage);
    }
    //send avcSequenceHeader
    if (publisher.videoCodec == 7) {
      let rtmpHeader = {
        chunkStreamID: 6,
        timestamp: 0,
        messageTypeID: 0x09,
        messageStreamID: 1
      };
      let flvMessage = NodeFlvSession.createFlvMessage(rtmpHeader, publisher.avcSequenceHeader);
      this.res.write(flvMessage);
    }
    //send gop cache
    if (publisher.flvGopCacheQueue != null) {
      for (let flvMessage of publisher.flvGopCacheQueue) {
        this.res.write(flvMessage);
      }
    }
    console.log(`[${this.TAG} play] join stream ` + this.playStreamPath);
    this.nodeEvent.emit('postPlay', this.id, this.playStreamPath, this.playArgs);
  }

  onPublish() {

  }

  static createFlvMessage(rtmpHeader, rtmpBody) {
    let FLVTagHeader = Buffer.alloc(11);
    FLVTagHeader[0] = rtmpHeader.messageTypeID;
    FLVTagHeader.writeUIntBE(rtmpBody.length, 1, 3);
    FLVTagHeader[4] = (rtmpHeader.timestamp >> 16) & 0xFF;
    FLVTagHeader[5] = (rtmpHeader.timestamp >> 8) & 0xFF;
    FLVTagHeader[6] = rtmpHeader.timestamp & 0xFF;
    FLVTagHeader[7] = (rtmpHeader.timestamp >> 24) & 0xFF;
    FLVTagHeader.writeUIntBE(0, 8, 3);
    let PreviousTagSizeN = Buffer.alloc(4);
    PreviousTagSizeN.writeUInt32BE(11 + rtmpBody.length);
    return Buffer.concat([FLVTagHeader, rtmpBody, PreviousTagSizeN]);
  }

}

module.exports = NodeFlvSession;
<commit_msg>Fix http/ws flv hevc error<commit_after>//
//  Created by Mingliang Chen on 17/8/4.
//  illuspas[a]gmail.com
//  Copyright (c) 2017 Nodemedia. All rights reserved.
//
const EventEmitter = require('events');
const URL = require('url');

const AMF = require('./node_core_amf');
const BufferPool = require('./node_core_bufferpool');
const NodeCoreUtils = require('./node_core_utils');

class NodeFlvSession extends EventEmitter {
  constructor(config, req, res) {
    super();
    this.config = config;
    this.req = req;
    this.res = res;
    this.bp = new BufferPool(this.handleData());
    this.bp.on('error', (e) => {

    });
    this.allow_origin = config.http.allow_origin == undefined ? '*' : config.http.allow_origin;
    this.isPublisher = false;
    this.playStreamPath = '';
    this.playArgs = null;
    this.nodeEvent = NodeCoreUtils.nodeEvent;

    this.on('connect', this.onConnect);
    this.on('play', this.onPlay);
    this.on('publish', this.onPublish);

    if (req.nmsConnectionType === 'ws') {
      this.res.on('message', this.onReqData.bind(this));
      this.res.on('close', this.onReqClose.bind(this));
      this.res.on('error', this.onReqError.bind(this));
      this.res.write = this.res.send;
      this.res.end = this.res.close;
      this.TAG = 'websocket-flv'
    } else {
      this.req.on('data', this.onReqData.bind(this));
      this.req.socket.on('close', this.onReqClose.bind(this));
      this.req.on('error', this.onReqError.bind(this));
      this.TAG = 'http-flv'
    }

  }

  run() {
    let method = this.req.method;
    let urlInfo = URL.parse(this.req.url, true);
    let streamPath = urlInfo.pathname.split('.')[0];
    let format = urlInfo.pathname.split('.')[1];
    this.connectCmdObj = { method, streamPath, query: urlInfo.query };
    this.nodeEvent.emit('preConnect', this.id, this.connectCmdObj);

    this.isStarting = true;
    this.bp.init();

    this.connectTime = new Date();

    if (format != 'flv') {
      console.log(`[${this.TAG}] Unsupported format=${format}`);
      this.res.statusCode = 403;
      this.res.end();
      return;
    }
    this.nodeEvent.emit('postConnect', this.id, this.connectCmdObj);
    if (method == 'GET') {
      //Play
      this.playStreamPath = streamPath;
      this.playArgs = urlInfo.query;
      console.log(`[${this.TAG} play] play stream ` + this.playStreamPath);
      this.emit('play');

    } else if (method == 'POST') {
      //Publish

      console.log(`[${this.TAG}] Unsupported method=` + method);
      this.res.statusCode = 405;
      this.res.end();
      return;
    } else {
      console.log(`[${this.TAG}] Unsupported method=` + method);
      this.res.statusCode = 405;
      this.res.end();
      return;
    }
  }

  onReqData(data) {
    this.bp.push(data);
  }

  onReqClose() {
    this.stop();
  }

  onReqError(e) {
    this.stop();
  }

  stop() {
    if (this.isStarting) {
      this.isStarting = false;
      this.bp.stop();
    }
  }

  reject() {
    this.stop();
  }

  * handleData() {

    console.log(`[${this.TAG} message parser] start`);
    while (this.isStarting) {
      if (this.bp.need(9)) {
        if (yield) break;
      }
    }

    console.log(`[${this.TAG} message parser] done`);
    if (this.isPublisher) {

    } else {
      let publisherId = this.publishers.get(this.playStreamPath);
      if (publisherId != null) {
        this.sessions.get(publisherId).players.delete(this.id);
        this.nodeEvent.emit('donePlay', this.id, this.playStreamPath, this.playArgs);
      }
    }
    this.nodeEvent.emit('doneConnect', this.id, this.connectCmdObj);
    this.res.end();
    this.idlePlayers.delete(this.id);
    this.sessions.delete(this.id);
    this.idlePlayers = null;
    this.publishers = null;
    this.sessions = null;
  }

  respondUnpublish() {
    this.res.end();
  }

  onConnect() {

  }

  onPlay() {

    this.nodeEvent.emit('prePlay', this.id, this.playStreamPath, this.playArgs);
    if (!this.isStarting) {
      return;
    }
    if (this.config.auth !== undefined && this.config.auth.play) {
      let results = NodeCoreUtils.verifyAuth(this.playArgs.sign, this.playStreamPath, this.config.auth.secret);
      if (!results) {
        console.log(`[${this.TAG}] Unauthorized. ID=${this.id} streamPath=${this.playStreamPath} sign=${this.playArgs.sign}`);
        this.res.statusCode = 401;
        this.res.end();
        return;
      }
    }

    if (!this.publishers.has(this.playStreamPath)) {
      console.log(`[${this.TAG} play] stream not found ` + this.playStreamPath);
      this.idlePlayers.add(this.id);
      return;
    }

    let publisherId = this.publishers.get(this.playStreamPath);
    let publisher = this.sessions.get(publisherId);
    let players = publisher.players;
    players.add(this.id);

    if (this.res.setHeader !== undefined) {
      this.res.setHeader('Content-Type', 'video/x-flv');
      this.res.setHeader('Access-Control-Allow-Origin', this.allow_origin);
    }

    //send FLV header
    let FLVHeader = Buffer.from([0x46, 0x4C, 0x56, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00]);
    if (publisher.isFirstAudioReceived) {
      FLVHeader[4] |= 0b00000100;
    }

    if (publisher.isFirstVideoReceived) {
      FLVHeader[4] |= 0b00000001;
    }
    this.res.write(FLVHeader);
    if (publisher.metaData != null) {
      //send Metadata
      let rtmpHeader = {
        chunkStreamID: 5,
        timestamp: 0,
        messageTypeID: 0x12,
        messageStreamID: 1
      };

      let metaDataFlvMessage = NodeFlvSession.createFlvMessage(rtmpHeader, publisher.metaData);
      this.res.write(metaDataFlvMessage);
    }
    //send aacSequenceHeader
    if (publisher.audioCodec == 10) {
      let rtmpHeader = {
        chunkStreamID: 4,
        timestamp: 0,
        messageTypeID: 0x08,
        messageStreamID: 1
      };
      let flvMessage = NodeFlvSession.createFlvMessage(rtmpHeader, publisher.aacSequenceHeader);
      this.res.write(flvMessage);
    }
    //send avcSequenceHeader
    if (publisher.videoCodec == 7 || publisher.videoCodec == 12) {
      let rtmpHeader = {
        chunkStreamID: 6,
        timestamp: 0,
        messageTypeID: 0x09,
        messageStreamID: 1
      };
      let flvMessage = NodeFlvSession.createFlvMessage(rtmpHeader, publisher.avcSequenceHeader);
      this.res.write(flvMessage);
    }
    //send gop cache
    if (publisher.flvGopCacheQueue != null) {
      for (let flvMessage of publisher.flvGopCacheQueue) {
        this.res.write(flvMessage);
      }
    }
    console.log(`[${this.TAG} play] join stream ` + this.playStreamPath);
    this.nodeEvent.emit('postPlay', this.id, this.playStreamPath, this.playArgs);
  }

  onPublish() {

  }

  static createFlvMessage(rtmpHeader, rtmpBody) {
    let FLVTagHeader = Buffer.alloc(11);
    FLVTagHeader[0] = rtmpHeader.messageTypeID;
    FLVTagHeader.writeUIntBE(rtmpBody.length, 1, 3);
    FLVTagHeader[4] = (rtmpHeader.timestamp >> 16) & 0xFF;
    FLVTagHeader[5] = (rtmpHeader.timestamp >> 8) & 0xFF;
    FLVTagHeader[6] = rtmpHeader.timestamp & 0xFF;
    FLVTagHeader[7] = (rtmpHeader.timestamp >> 24) & 0xFF;
    FLVTagHeader.writeUIntBE(0, 8, 3);
    let PreviousTagSizeN = Buffer.alloc(4);
    PreviousTagSizeN.writeUInt32BE(11 + rtmpBody.length);
    return Buffer.concat([FLVTagHeader, rtmpBody, PreviousTagSizeN]);
  }

}

module.exports = NodeFlvSession;
<|endoftext|>


<commit_before>/**
 *  @add jQuery.fn
 */
steal.plugins("jquery/dom",'jquery/lang/rsplit').then(function($) {
var radioCheck = /radio|checkbox/i,
	keyBreaker = /[^\[\]]+/g,
	numberMatcher = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/

	isNumber = function(value) {
	   if(typeof value == 'number') return true;
	   if(typeof value != 'string') return false;
	   return value.match(numberMatcher);
	};

$.fn.extend({
	/**
	 * @parent dom
	 * @download dist/jquery.formparams.js
	 * @plugin jquery/dom/form_params
	 * @test jquery/dom/form_params/qunit.html
	 *
Returns an object of name-value pairs that represents values in a form.
	 * It is able to nest values whose element's name has square brackets.

	 * Example html:
	 * @codestart html
	 * <form>
	 *   <input name="foo[bar]" value='2'/>
	 *   <input name="foo[ced]" value='4'/>
	 * <form/>
	 * @codeend
	 * Example code:
	 * @codestart
	 * $('form').formParams() //-> { foo:{bar:2, ced: 4} }
	 * @codeend
	 *
	 * @demo jquery/dom/form_params/form_params.html
	 *
	 * @param {Boolean} [convert] True if strings that look like numbers and booleans should be converted.  Defaults to true.
	 * @return {Object} An object of name-value pairs.
	 */
	formParams: function(convert) {
	   var data = {};
	   if(this[0].nodeName.toLowerCase() == 'form' && this[0].elements){

		   return jQuery( jQuery.makeArray(this[0].elements) ).getParams(convert);
	   }
	   return jQuery("input, textarea, select", this[0]).getParams(convert);
	},
	getParams : function(convert){
		var data = {},
			current,
			convert = convert === undefined ? true : convert;

		this.each(function(){
			var el = this;
			//if we are submit, ignore
			if (el.type && el.type.toLowerCase() == 'submit') {
				return;
			}

			var key = el.name,
				value = $.fn.val.call([el]) || $.data(el,"value"),
				isRadioCheck = radioCheck.test(el.type),
				parts = key.match(keyBreaker),
				write = !isRadioCheck || !!el.checked, //overwrite the value
				append = false, //make an array of values
				lastPart;

			// we want true / false for checkboxes

			if( convert ) {
				if(isNumber(value)){
					value = parseFloat(value);
				}else if(value === 'true' || value === 'false'){
					value = Boolean(value);
				}

			}

			// go through and create nested objects
			current = data;
			for(var i=0; i < parts.length - 1; i++){
				if(!current[parts[i]]){
					current[parts[i]] = {}
				}
				current = current[parts[i]];
			}
			lastPart = parts[parts.length - 1];

			//now we are on the last part, set the value
			if( lastPart in current && el.type.toLowerCase() === "checkbox"){
				if( !$.isArray(current[lastPart]) ){
					current[lastPart] = current[lastPart] === undefined ? [] : [ current[lastPart] ];
				}
				if(write){
					current[lastPart].push(value);
				}
			}else{
				current[lastPart] = write ? value : undefined;
			}

		})
		return data;
	}
});

});<commit_msg>right download link<commit_after>/**
 *  @add jQuery.fn
 */
steal.plugins("jquery/dom",'jquery/lang/rsplit').then(function($) {
var radioCheck = /radio|checkbox/i,
	keyBreaker = /[^\[\]]+/g,
	numberMatcher = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/

	isNumber = function(value) {
	   if(typeof value == 'number') return true;
	   if(typeof value != 'string') return false;
	   return value.match(numberMatcher);
	};

$.fn.extend({
	/**
	 * @parent dom
	 * @download jquery/dist/jquery.formparams.js
	 * @plugin jquery/dom/form_params
	 * @test jquery/dom/form_params/qunit.html
	 *
Returns an object of name-value pairs that represents values in a form.
	 * It is able to nest values whose element's name has square brackets.

	 * Example html:
	 * @codestart html
	 * <form>
	 *   <input name="foo[bar]" value='2'/>
	 *   <input name="foo[ced]" value='4'/>
	 * <form/>
	 * @codeend
	 * Example code:
	 * @codestart
	 * $('form').formParams() //-> { foo:{bar:2, ced: 4} }
	 * @codeend
	 *
	 * @demo jquery/dom/form_params/form_params.html
	 *
	 * @param {Boolean} [convert] True if strings that look like numbers and booleans should be converted.  Defaults to true.
	 * @return {Object} An object of name-value pairs.
	 */
	formParams: function(convert) {
	   var data = {};
	   if(this[0].nodeName.toLowerCase() == 'form' && this[0].elements){

		   return jQuery( jQuery.makeArray(this[0].elements) ).getParams(convert);
	   }
	   return jQuery("input, textarea, select", this[0]).getParams(convert);
	},
	getParams : function(convert){
		var data = {},
			current,
			convert = convert === undefined ? true : convert;

		this.each(function(){
			var el = this;
			//if we are submit, ignore
			if (el.type && el.type.toLowerCase() == 'submit') {
				return;
			}

			var key = el.name,
				value = $.fn.val.call([el]) || $.data(el,"value"),
				isRadioCheck = radioCheck.test(el.type),
				parts = key.match(keyBreaker),
				write = !isRadioCheck || !!el.checked, //overwrite the value
				append = false, //make an array of values
				lastPart;

			// we want true / false for checkboxes

			if( convert ) {
				if(isNumber(value)){
					value = parseFloat(value);
				}else if(value === 'true' || value === 'false'){
					value = Boolean(value);
				}

			}

			// go through and create nested objects
			current = data;
			for(var i=0; i < parts.length - 1; i++){
				if(!current[parts[i]]){
					current[parts[i]] = {}
				}
				current = current[parts[i]];
			}
			lastPart = parts[parts.length - 1];

			//now we are on the last part, set the value
			if( lastPart in current && el.type.toLowerCase() === "checkbox"){
				if( !$.isArray(current[lastPart]) ){
					current[lastPart] = current[lastPart] === undefined ? [] : [ current[lastPart] ];
				}
				if(write){
					current[lastPart].push(value);
				}
			}else{
				current[lastPart] = write ? value : undefined;
			}

		})
		return data;
	}
});

});<|endoftext|>


<commit_before>var app = angular.module('refactorServicios', ['ngRoute']);

app.config(function ($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'listado-tareas.html',
            controller: 'ListadoTareasController'
        })
        .when('/tarea', {
            templateUrl: 'tarea.html',
            controller: 'NuevaTareaController'
        })
        .when('/tarea/:position', {
            templateUrl: 'tarea.html',
            controller: 'EdicionTareaController'
        })
        .otherwise({ redirectTo: "/" });
});

app.controller("ListadoTareasController", function ($scope, TareasService) {
    $scope.tareas = TareasService.getTareas();
    $scope.eliminarFinalaizadas = function () {
        //lo que quieran hacer relacionado con la vista o con validaciones
        TareasService.eliminarFinalizadas();
    }
});

app.controller("NuevaTareaController", function ($scope, $location, TareasService) {
    $scope.tarea = {};

    $scope.guardarTarea = function () {
        TareasService.nuevaTarea($scope.tarea);
        $location.path('/');
    }
});

app.controller("EdicionTareaController", function ($scope, $routeParams, $location, TareasService) {
    var tareas = TareasService.getTareas();
    $scope.tarea = tareas[$routeParams.position];

    $scope.guardarTarea = function () {
        $location.path('/');
    }
});

app.factory("TareasService", function ($http) {

    var tareas = [];

    var TareasService = {};
    TareasService.getTareas = getTareas;
    TareasService.nuevaTarea = nuevaTarea;
    TareasService.eliminarFinalizadas = eliminarFinalizadas;

    initService();

    return TareasService;

    function initService(){
        $http.get("datosFalsos.json").then(function (response) {
            tareas.splice(0, tareas.length);
            _.each(response.data, function(tarea){
                tareas.push(tarea)
            });
        });
    }

    function getTareas() {
        return tareas;
    }

    function nuevaTarea(tarea) {
        tareas.push(tarea);
    }

    function eliminarFinalizadas() {
        _.remove(tareas, function (tarea) {
            return tarea.realizada;
        });
    }

});
<commit_msg>$apply<commit_after>var app = angular.module('refactorServicios', ['ngRoute']);

app.config(function ($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'listado-tareas.html',
            controller: 'ListadoTareasController'
        })
        .when('/tarea', {
            templateUrl: 'tarea.html',
            controller: 'NuevaTareaController'
        })
        .when('/tarea/:position', {
            templateUrl: 'tarea.html',
            controller: 'EdicionTareaController'
        })
        .otherwise({ redirectTo: "/" });
});

app.controller("ListadoTareasController", function ($scope, TareasService) {
    $scope.tareas = TareasService.getTareas();
    $scope.eliminarFinalaizadas = function () {
        //lo que quieran hacer relacionado con la vista o con validaciones
        TareasService.eliminarFinalizadas();
    }
});

app.controller("NuevaTareaController", function ($scope, $location, TareasService) {
    $scope.tarea = {};

    $scope.guardarTarea = function () {
        TareasService.nuevaTarea($scope.tarea);
        $location.path('/');
    }
});

app.controller("EdicionTareaController", function ($scope, $routeParams, $location, TareasService) {
    var tareas = TareasService.getTareas();
    $scope.tarea = tareas[$routeParams.position];

    $scope.guardarTarea = function () {
        $location.path('/');
    }
});

app.factory("TareasService", function ($http, $timeout) {

    var tareas = [];

    var TareasService = {};
    TareasService.getTareas = getTareas;
    TareasService.nuevaTarea = nuevaTarea;
    TareasService.eliminarFinalizadas = eliminarFinalizadas;

    initService();

    return TareasService;

    function initService(){
        $http.get("datosFalsos.json").then(function (response) {
            $timeout(function(){
                tareas.splice(0, tareas.length);
                _.each(response.data, function(tarea){
                    tareas.push(tarea)
                });
            }, 0);
        });
    }

    function getTareas() {
        return tareas;
    }

    function nuevaTarea(tarea) {
        tareas.push(tarea);
    }

    function eliminarFinalizadas() {
        _.remove(tareas, function (tarea) {
            return tarea.realizada;
        });
    }

});
<|endoftext|>


<commit_before>THREE.neonShader = {
	globals: {
		saturation: { type: 'f', value: url.number( 'saturation', 0.21 ) },
		sepia: { type: 'f', value: url.number( 'sepia', 3.5 ) },
		sepiaCol1: { type: 'c', value: new THREE.Color( 0x1488b9 ) },
		sepiaCol2: { type: 'c', value: new THREE.Color( 0x10bfca ) },
		neonCol: { type: 'c', value: new THREE.Color( 0x3109eb ) },
		neon: { type: 'f', value: url.number( 'neon', 0.0 ) },
		time: { type: 'f', value: url.number( 'neon', 0.0 ) },
		cursor: { type: 'v3', value: new THREE.Vector3() },
		motionVector: { type: 'v3', value: new THREE.Vector3() },
		yrot: { type: 'f', value: 0 },
		neonFade: { type: 'f', value: 0.62 },
		neonGlow: { type: 'f', value: 0.85 },
		neonFreq1: { type: 'f', value: 1.1 },
		neonFreq2  : { type: 'f', value: 2.0 },
		neonNearClip: { type: 'f', value: 0.0 }
	}
}

THREE.neonShader.loadTextFile = function( url ) {
	var result;
	var req = new XMLHttpRequest();
	req.onerror = function() {
		console.log( "Error: request error on " + url );
	};
	req.onload = function() {
		result = this.responseText;
	};
	req.open( "GET", url, false );
	req.send();
	return result;
};

THREE.neonShader.loadTextFileInject = function( url ) {
	var fileStr = THREE.neonShader.loadTextFile( url );
	var matches = fileStr.match( /#inject .+/g );
	if ( !matches ) return fileStr;
	for ( var i = 0; i < matches.length; i++ ) {
		var injectLine = matches[i];
		var injectUrl = injectLine.split( " " )[1];
		var injectFileStr = THREE.neonShader.loadTextFileInject( injectUrl );
		fileStr = fileStr.replace( injectLine, injectFileStr );
	}
	return fileStr;
};

THREE.neonShader.load = function( url ) {
	var src = THREE.neonShader.loadTextFileInject( url );
	var lines = src.match( /.+/g );
	var srcFormatted = '';
	for ( var i = 0; i < lines.length; i++ ) {
		var line = '"' + lines[i] + '",';
		srcFormatted += line;
		srcFormatted += '\r\n';
	}
	console.log( url, ':\n' );
	console.log( srcFormatted );
	return src;
}

THREE.neonShader._vert = [

].join( '\n' );
// NOTE: Uncomment line below to use glsl shader source.
THREE.neonShader._vert = THREE.neonShader.load( '../release/src/shaders/vert.glsl' );

THREE.neonShader._frag = [

].join( '\n' );
// NOTE: Uncomment line below to use glsl shader source.
THREE.neonShader._frag = THREE.neonShader.load( '../release/src/shaders/frag.glsl' );

THREE.neonShader._uniforms = {
	color: { type: 'c', value: new THREE.Color( 0xffffff ) },
	fogColor: { type: 'c', value: new THREE.Color( 0x000000 ) },
	fogNear: { type: 'f', value: 0 },
	fogFar: { type: 'f', value: 1 }
};

THREE.neonShader.basicShader = new THREE.ShaderMaterial( {
	fog: true,
	side: THREE.FrontSide,
	uniforms: THREE.UniformsUtils.clone( THREE.neonShader._uniforms ),
	vertexShader: THREE.neonShader._vert,
	fragmentShader: THREE.neonShader._frag
} );

THREE.neonShader.grassShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.grassShader.setValues( {
	defines: {
		USE_GRASS: '',
		USE_INSTANCING: ''
	},
	uniforms: THREE.UniformsUtils.merge( [
		THREE.neonShader._uniforms, {
			size: { type: 'f', value: 1 }
		}
	] )
} );

THREE.neonShader.roadShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.roadShader.setValues( {
	defines: {
		USE_ROAD: '',
		USE_FAKE_SHADOW: ''
	},
	uniforms: THREE.UniformsUtils.merge( [
		THREE.neonShader._uniforms, {
			subdivisions: { type: 'f', value: 32 },
			curvature: { type: 'f', value: 1 },
			size: { type: 'f', value: 1 },
			median: { type: 'c', value: new THREE.Color( 'red' ) }
		}
	] )
} );

THREE.neonShader.skinnedShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.skinnedShader.setValues( {
	side: THREE.DoubleSide,
	vertexColors: true,
	skinning: true,
	uniforms: THREE.UniformsUtils.merge( [
		THREE.neonShader._uniforms, {
			clip: { type: 'v2', value: new THREE.Vector2( -1e10, 1e10 ) }
		}
	] )
} );
THREE.neonShader.skinnedShader.defines = { USE_CLIPPING: '' };

THREE.neonShader.swirlShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.swirlShader.uniforms = THREE.UniformsUtils.merge( [
	THREE.neonShader._uniforms, {
		progress: { type: 'f', value: 0 }
	}
] );
THREE.neonShader.swirlShader.defines = { USE_SWIRL: '' };

THREE.neonShader.floorShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.floorShader.defines = { USE_FAKE_SHADOW: '' };

THREE.neonShader.waveShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.waveShader.defines = { USE_WAVE: '' };
THREE.neonShader.waveShader.vertexColors = true;
THREE.neonShader.waveShader.side = THREE.DoubleSide;

THREE.neonShader.backSided = THREE.neonShader.basicShader.clone();
THREE.neonShader.backSided.defines = { DONTUSE_NEON: '' };
THREE.neonShader.backSided.side = THREE.BackSide;
THREE.neonShader.backSided.depthWrite = false;

THREE.neonShader.vertexColoredDoubleSided = THREE.neonShader.basicShader.clone();
THREE.neonShader.vertexColoredDoubleSided.vertexColors = true;
THREE.neonShader.vertexColoredDoubleSided.defines = { USE_FAKE_SHADOW: '' };
THREE.neonShader.vertexColoredDoubleSided.side = THREE.DoubleSide;

THREE.neonShader.vertexColored = THREE.neonShader.basicShader.clone();
THREE.neonShader.vertexColored.vertexColors = true;
THREE.neonShader.vertexColored.defines = { USE_FAKE_SHADOW: '' };

THREE.neonShader.doubleSided = THREE.neonShader.roadShader.clone();
THREE.neonShader.doubleSided.side = THREE.DoubleSide;

for ( var i in THREE.neonShader  ) {
	if ( THREE.neonShader[i] instanceof THREE.ShaderMaterial ) {
		for ( var j in THREE.neonShader.globals ) {
			THREE.neonShader[i].uniforms[j] = THREE.neonShader.globals[j];
		}
	}
}
<commit_msg>compiled shaders.<commit_after>THREE.neonShader = {
	globals: {
		saturation: { type: 'f', value: url.number( 'saturation', 0.21 ) },
		sepia: { type: 'f', value: url.number( 'sepia', 3.5 ) },
		sepiaCol1: { type: 'c', value: new THREE.Color( 0x1488b9 ) },
		sepiaCol2: { type: 'c', value: new THREE.Color( 0x10bfca ) },
		neonCol: { type: 'c', value: new THREE.Color( 0x3109eb ) },
		neon: { type: 'f', value: url.number( 'neon', 0.0 ) },
		time: { type: 'f', value: url.number( 'neon', 0.0 ) },
		cursor: { type: 'v3', value: new THREE.Vector3() },
		motionVector: { type: 'v3', value: new THREE.Vector3() },
		yrot: { type: 'f', value: 0 },
		neonFade: { type: 'f', value: 0.62 },
		neonGlow: { type: 'f', value: 0.85 },
		neonFreq1: { type: 'f', value: 1.1 },
		neonFreq2  : { type: 'f', value: 2.0 },
		neonNearClip: { type: 'f', value: 0.0 }
	}
}

THREE.neonShader.loadTextFile = function( url ) {
	var result;
	var req = new XMLHttpRequest();
	req.onerror = function() {
		console.log( "Error: request error on " + url );
	};
	req.onload = function() {
		result = this.responseText;
	};
	req.open( "GET", url, false );
	req.send();
	return result;
};

THREE.neonShader.loadTextFileInject = function( url ) {
	var fileStr = THREE.neonShader.loadTextFile( url );
	var matches = fileStr.match( /#inject .+/g );
	if ( !matches ) return fileStr;
	for ( var i = 0; i < matches.length; i++ ) {
		var injectLine = matches[i];
		var injectUrl = injectLine.split( " " )[1];
		var injectFileStr = THREE.neonShader.loadTextFileInject( injectUrl );
		fileStr = fileStr.replace( injectLine, injectFileStr );
	}
	return fileStr;
};

THREE.neonShader.load = function( url ) {
	var src = THREE.neonShader.loadTextFileInject( url );
	var lines = src.match( /.+/g );
	var srcFormatted = '';
	for ( var i = 0; i < lines.length; i++ ) {
		var line = '"' + lines[i] + '",';
		srcFormatted += line;
		srcFormatted += '\r\n';
	}
	console.log( url, ':\n' );
	console.log( srcFormatted );
	return src;
}

THREE.neonShader._vert = [
	"varying vec2 vUv;",
	"varying vec4 mPosition;",
	"varying vec4 mvPosition;",
	"varying vec3 vColor;",
	"uniform float time;",
	"uniform float curvature;",
	"uniform float size;",
	"#ifndef USE_COLOR",
	"	uniform vec3 color;",
	"#endif",
	"float PI = 3.141592653589793;",
	"#ifdef USE_SKINNING",
	"	uniform mat4 bindMatrix;",
	"uniform mat4 bindMatrixInverse;",
	"#ifdef BONE_TEXTURE",
	"  uniform sampler2D boneTexture;",
	"  uniform int boneTextureSize;",
	"  mat4 getBoneMatrix( const in float i ) {",
	"    float j = i * 4.0;",
	"    float x = mod( j, float( boneTextureSize ) );",
	"    float y = floor( j / float( boneTextureSize ) );",
	"    float dx = 1.0 / float( boneTextureSize );",
	"    float dy = 1.0 / float( boneTextureSize );",
	"    y = dy * ( y + 0.5 );",
	"    vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
	"    vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
	"    vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
	"    vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",
	"    mat4 bone = mat4( v1, v2, v3, v4 );",
	"    return bone;",
	"  }",
	"#else",
	"  uniform mat4 boneMatrices[ MAX_BONES ];",
	"  mat4 getBoneMatrix( const in float i ) {",
	"    mat4 bone = boneMatrices[ int(i) ];",
	"    return bone;",
	"  }",
	"#endif",
	"#endif",
	"#ifdef USE_INSTANCING",
	"	attribute vec3 instancedTranslation;",
	"	attribute vec3 instancedScale;",
	"#endif",
	"void main() {",
	"	vUv = uv;",
	"	vColor = color;",
	"	vec3 pos = vec3( position );",
	"	#ifdef USE_SKINNING",
	"		/* skinbase_vertex */",
	"mat4 boneMatX = getBoneMatrix( skinIndex.x );",
	"mat4 boneMatY = getBoneMatrix( skinIndex.y );",
	"mat4 boneMatZ = getBoneMatrix( skinIndex.z );",
	"mat4 boneMatW = getBoneMatrix( skinIndex.w );",
	"vec4 skinVertex = bindMatrix * vec4( position.xyz, 1.0 );",
	"vec4 skinned = vec4( 0.0 );",
	"skinned += boneMatX * skinVertex * skinWeight.x;",
	"skinned += boneMatY * skinVertex * skinWeight.y;",
	"skinned += boneMatZ * skinVertex * skinWeight.z;",
	"skinned += boneMatW * skinVertex * skinWeight.w;",
	"pos = ( bindMatrixInverse * skinned ).xyz;",
	"	#endif",
	"	#ifdef USE_GRASS",
	"		float pct = clamp( pos.y, 0.0, 1.0 );",
	"		float taper = sin( pow( pct, 0.5 ) * PI );",
	"		pos.x *= taper;",
	"		pos.z *= taper;",
	"	#endif",
	"	#ifdef USE_ROAD",
	"		float x = pos.x / size;",
	"		float y = pos.y / size;",
	"		float x2 = x * 2.0;",
	"		float y2 = y * 2.0;",
	"		float dist = curvature * sqrt( x2 * x2 + y2 * y2 );",
	"		pos.z = size * ( dist * dist ) / 2.0;",
	"	#endif",
	"	#ifdef USE_WAVE",
	"		vec4 t = projectionMatrix * vec4( 1.0 );",
	"		float osc = ( 1.0 + sin( time + PI * ( t.x + t.y + t.z ) / 3.0 ) ) / 2.0;",
	"		float sway = pow( pos.y, 2.0 ) * osc;",
	"		pos.x += sway / 100.0;",
	"	#endif",
	"	#ifdef USE_INSTANCING",
	"		pos *= instancedScale;",
	"		pos += instancedTranslation;",
	"	#endif",
	"	mPosition = modelMatrix * vec4( pos, 1.0 );",
	"	mvPosition = viewMatrix * mPosition;",
	"	gl_Position = projectionMatrix * mvPosition;",
	"}",
].join( '\n' );
// NOTE: Uncomment line below to use glsl shader source.
// THREE.neonShader._vert = THREE.neonShader.load( '../release/src/shaders/vert.glsl' );

THREE.neonShader._frag = [
	"const float PI = 3.141592653589793;",
	"const vec3 b = vec3( 0.0, 69.0, 116.0 ) * 1.5;",
	"const vec3 a = vec3( 89.0, 188.0, 255.0 ) * 1.5;",
	"uniform vec3 fogColor;",
	"uniform float fogNear;",
	"uniform float fogFar;",
	"uniform float sepia;",
	"uniform vec3 sepiaCol1;",
	"uniform vec3 sepiaCol2;",
	"uniform vec3 neonCol;",
	"uniform float saturation;",
	"uniform float neon;",
	"uniform float time;",
	"uniform float size;",
	"uniform vec3 cursor;",
	"uniform vec2 clip;",
	"uniform float yrot;",
	"uniform float progress;",
	"varying vec2 vUv;",
	"varying vec3 vColor;",
	"varying vec4 mPosition;",
	"varying vec4 mvPosition;",
	"uniform mat4 projectionMatrix;",
	"uniform float neonFade;",
	"uniform float neonGlow;",
	"uniform float neonFreq1;",
	"uniform float neonFreq2;",
	"uniform float neonNearClip;",
	"vec3 sepiaColor( vec3 col ) {",
	"	float amount = 2.0;",
	"	vec4 clipSpace = projectionMatrix * mvPosition;",
	"	vec2 coord = ( clipSpace.xyz / clipSpace.w ).xy;",
	"	float radius = length( ( coord )  ) / 1.3;",
	"	float magnitude = ( 1.0 - radius ) * ( amount - 1.0 );",
	"	vec3 layer = mix( sepiaCol2.rgb * 2.0, sepiaCol1.rgb, clamp( magnitude, 0.0, 1.0 ) );",
	"	return  col - layer * 0.1 * sepia;",
	"}",
	"vec3 neonFog( vec3 col ) {",
	"	float fogDepth = length( mPosition.xz );",
	"	float fogFactor = smoothstep( fogNear, fogFar, fogDepth );",
	"	return mix( col, fogColor, fogFactor );",
	"}",
	"mat3 rotateY( float rad ) {",
	"	float c = cos( rad );",
	"	float s = sin( rad );",
	"	return mat3(",
	"		c, 0.0, -s,",
	"		0.0, 1.0, 0.0,",
	"		s, 0.0, c",
	"	);",
	"}",
	"float neonNoise( vec3 pos ) {",
	"	float dist = sin( pos.x * 0.32 ) + sin( pos.y * 0.26 ) + sin( pos.z * 0.45 ) +",
	"		sin( pos.x * 0.078 ) + sin( pos.y * 0.089 ) + sin( pos.z * 0.091 ) +",
	"		sin( pos.x * 0.12 ) + sin( pos.y * 0.34 ) + sin( pos.z * 0.23 ) +",
	"		sin( sqrt( pos.x * pos.x + pos.y * pos.y + pos.z * pos.z ) * 0.5 );",
	"		float f = dist * neonFreq2;",
	"		return abs( sin( f ) );",
	"}",
	"vec3 neonFunc( vec3 col ) {",
	"	vec3 p = rotateY( - yrot ) * ( mPosition.xyz ) + cursor;",
	"	float neonFactor = neonNoise( p * neonFreq1 + vec3( 0.0, - time * 0.5, 0.0 ) );",
	"	float neonFactorFade = smoothstep( min( 2.0 * ( neonFade * neon ) - 1.0, 1.0 ), 1.0, neonFactor );",
	"	vec3 nCol = mix( col * neonCol * 6.0 + neonCol * 2.0, col, pow( neonFactorFade, 5.2 * neonGlow ) );",
	"	nCol = mix( fogColor, nCol, pow( neonFactorFade, 3.0 ) );",
	"	col = mix( col, nCol, neon );",
	"	return col;",
	"}",
	"#ifndef USE_COLOR",
	"	uniform vec3 color;",
	"#endif",
	"#ifdef USE_ROAD",
	"	uniform float subdivisions;",
	"uniform vec3 median;",
	"vec3 roadFunc() {",
	"	/*",
	"	float threshold = 6.0 / size;",
	"	vec2 wUv = vec2( mPosition.zx ) / size - vec2( 0.5 );",
	"	vec2 rCursor = cursor.zx / size;",
	"	vec2 pos = rCursor + wUv;",
	"	pos = mod( subdivisions * pos, 1.0 );",
	"	vec2 isMedian = vec2( sin( pos * PI ) );",
	"	vec2 isIntersection = vec2( 1.0 - isMedian.y, 1.0 - isMedian.x );",
	"	isMedian = step( vec2( threshold ), isMedian );",
	"	isIntersection = step( vec2( 0.66 ), isIntersection );",
	"	float t = clamp( isMedian.x + isIntersection.x, 0.0, 1.0 );",
	"	vec3 layer = mix( median, color, t );",
	"	t = clamp( isMedian.y + isIntersection.y, 0.0, 1.0 );",
	"	layer = mix( median, layer, t );",
	"	return layer;",
	"	*/",
	"	return color;",
	"}",
	"#endif",
	"void main() {",
	"	vec3 col = vColor;",
	"	#ifdef USE_CLIPPING",
	"		if ( mPosition.y < clip.x * 2.0 || mPosition.y > clip.y * 2.0 ) discard;",
	"	#endif",
	"	#ifdef USE_GRASS",
	"		col = mix( vec3( 0.55, 0.98, 0.45 ), vec3( 0.559, 0.776, 0.247 ), abs( vUv.y ) );",
	"	#endif",
	"	#ifdef USE_ROAD",
	"		col = roadFunc();",
	"	#endif",
	"	#ifdef USE_FAKE_SHADOW",
	"		float dist = min( length( mPosition.xyz ) * .06, 1.0 );",
	"		float shadow = smoothstep( 0.09, 0.15, pow( dist, 0.5 ) );",
	"		col = mix( col * 0.75, col, shadow );",
	"	#endif",
	"	#ifdef USE_SWIRL",
	"		col = mix( col, vec3( 0.0 ), smoothstep( 0.0, 1.0, length( mPosition.xz ) ) );",
	"		float p = (1.0 - progress) * ( 1.0 + 0.6 ) - 0.3;",
	"		if (vUv.y > p || vUv.y < (p - 0.3)) discard;",
	"	#endif",
	"	col = mix( vec3( length( col ) * 0.75 ), col, saturation );",
	"	#ifndef DONTUSE_NEON",
	"		col = neonFunc( col );",
	"	#endif",
	"	#ifdef USE_FOG",
	"		col = neonFog( col );",
	"	#endif",
	"	col = sepiaColor( col );",
	"	gl_FragColor = vec4( col, 1.0 );",
	"}",
].join( '\n' );
// NOTE: Uncomment line below to use glsl shader source.
// THREE.neonShader._frag = THREE.neonShader.load( '../release/src/shaders/frag.glsl' );

THREE.neonShader._uniforms = {
	color: { type: 'c', value: new THREE.Color( 0xffffff ) },
	fogColor: { type: 'c', value: new THREE.Color( 0x000000 ) },
	fogNear: { type: 'f', value: 0 },
	fogFar: { type: 'f', value: 1 }
};

THREE.neonShader.basicShader = new THREE.ShaderMaterial( {
	fog: true,
	side: THREE.FrontSide,
	uniforms: THREE.UniformsUtils.clone( THREE.neonShader._uniforms ),
	vertexShader: THREE.neonShader._vert,
	fragmentShader: THREE.neonShader._frag
} );

THREE.neonShader.grassShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.grassShader.setValues( {
	defines: {
		USE_GRASS: '',
		USE_INSTANCING: ''
	},
	uniforms: THREE.UniformsUtils.merge( [
		THREE.neonShader._uniforms, {
			size: { type: 'f', value: 1 }
		}
	] )
} );

THREE.neonShader.roadShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.roadShader.setValues( {
	defines: {
		USE_ROAD: '',
		USE_FAKE_SHADOW: ''
	},
	uniforms: THREE.UniformsUtils.merge( [
		THREE.neonShader._uniforms, {
			subdivisions: { type: 'f', value: 32 },
			curvature: { type: 'f', value: 1 },
			size: { type: 'f', value: 1 },
			median: { type: 'c', value: new THREE.Color( 'red' ) }
		}
	] )
} );

THREE.neonShader.skinnedShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.skinnedShader.setValues( {
	side: THREE.DoubleSide,
	vertexColors: true,
	skinning: true,
	uniforms: THREE.UniformsUtils.merge( [
		THREE.neonShader._uniforms, {
			clip: { type: 'v2', value: new THREE.Vector2( -1e10, 1e10 ) }
		}
	] )
} );
THREE.neonShader.skinnedShader.defines = { USE_CLIPPING: '' };

THREE.neonShader.swirlShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.swirlShader.uniforms = THREE.UniformsUtils.merge( [
	THREE.neonShader._uniforms, {
		progress: { type: 'f', value: 0 }
	}
] );
THREE.neonShader.swirlShader.defines = { USE_SWIRL: '' };

THREE.neonShader.floorShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.floorShader.defines = { USE_FAKE_SHADOW: '' };

THREE.neonShader.waveShader = THREE.neonShader.basicShader.clone();
THREE.neonShader.waveShader.defines = { USE_WAVE: '' };
THREE.neonShader.waveShader.vertexColors = true;
THREE.neonShader.waveShader.side = THREE.DoubleSide;

THREE.neonShader.backSided = THREE.neonShader.basicShader.clone();
THREE.neonShader.backSided.defines = { DONTUSE_NEON: '' };
THREE.neonShader.backSided.side = THREE.BackSide;
THREE.neonShader.backSided.depthWrite = false;

THREE.neonShader.vertexColoredDoubleSided = THREE.neonShader.basicShader.clone();
THREE.neonShader.vertexColoredDoubleSided.vertexColors = true;
THREE.neonShader.vertexColoredDoubleSided.defines = { USE_FAKE_SHADOW: '' };
THREE.neonShader.vertexColoredDoubleSided.side = THREE.DoubleSide;

THREE.neonShader.vertexColored = THREE.neonShader.basicShader.clone();
THREE.neonShader.vertexColored.vertexColors = true;
THREE.neonShader.vertexColored.defines = { USE_FAKE_SHADOW: '' };

THREE.neonShader.doubleSided = THREE.neonShader.roadShader.clone();
THREE.neonShader.doubleSided.side = THREE.DoubleSide;

for ( var i in THREE.neonShader  ) {
	if ( THREE.neonShader[i] instanceof THREE.ShaderMaterial ) {
		for ( var j in THREE.neonShader.globals ) {
			THREE.neonShader[i].uniforms[j] = THREE.neonShader.globals[j];
		}
	}
}
<|endoftext|>


<commit_before>import { extend } from 'core/util';
import { trim } from 'core/util/strings';
import {
    on,
    off,
    removeDomNode,
    stopPropagation,
    TRANSFORM,
    TRANSFORMORIGIN,
    TRANSITION
} from 'core/util/dom';
import Browser from 'core/Browser';
import Class from 'core/Class';
import Eventable from 'core/Eventable';
import Point from 'geo/Point';
import Size from 'geo/Size';
import Geometry from 'geometry/Geometry';

/**
 * @property {Object} options
 * @property {Boolean} [options.eventsToStop='mousedown dblclick']  - UI's dom events to stop propagation.
 * @property {Number}  [options.dx=0]     - pixel offset on x axis
 * @property {Number}  [options.dy=0]     - pixel offset on y axis
 * @property {Boolean} [options.autoPan=false]  - set it to false if you don't want the map to do panning animation to fit the opened UI.
 * @property {Boolean} [options.autoPanDuration=600]    - duration for auto panning animation.
 * @property {Boolean} [options.single=true]    - whether the UI is a global single one, only one UI will be shown at the same time if set to true.
 * @property {Boolean} [options.animation=null]         - fade | scale | fade,scale, add animation effect when showing and hiding.
 * @property {Number}  [options.animationDuration=300]  - animation duration, in milliseconds.
 * @memberOf ui.UIComponent
 * @instance
 */
const options = {
    'eventsToStop': 'mousedown dblclick',
    'dx': 0,
    'dy': 0,
    'autoPan': false,
    'autoPanDuration' : 600,
    'single': true,
    'animation': 'scale',
    'animationOnHide': true,
    'animationDuration': 500
};

/**
 * @classdesc
 * Base class for all the UI component classes, a UI component is a HTMLElement positioned with geographic coordinate.

 * It is abstract and not intended to be instantiated.
 *
 * @category ui
 * @abstract
 * @mixes Eventable
 * @memberOf ui
 * @extends Class
 */
class UIComponent extends Eventable(Class) {

    /**
     *  Some instance methods subclasses needs to implement:

     *

     * 1. Optional, returns the Dom element's position offset

     * function getOffset : Point

     *

     * 2. Method to create UI's Dom element

     * function buildOn : HTMLElement

     *

     * 3 Optional, to provide an event map to register event listeners.

     * function getEvents : void

     * 4 Optional, a callback when dom is removed.

     * function onDomRemove : void

     * 5 Optional, a callback when UI Component is removed.

     * function onRemove : void

     * @param  {Object} options configuration options
     */
    constructor(options) {
        super(options);
    }

    /**
     * Adds the UI Component to a geometry or a map
     * @param {Geometry|Map} owner - geometry or map to addto.
     * @returns {ui.UIComponent} this
     * @fires ui.UIComponent#add
     */
    addTo(owner) {
        this._owner = owner;
        // first time
        this._switchEvents('on');
        if (this.onAdd) {
            this.onAdd();
        }
        /**
         * add event.
         *
         * @event ui.UIComponent#add
         * @type {Object}
         * @property {String} type - add
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('add');
        return this;
    }

    /**
     * Get the map it added to
     * @return {Map} map instance
     * @override
     */
    getMap() {
        if (!this._owner) {
            return null;
        }
        // is a map
        if (this._owner.getBaseLayer) {
            return this._owner;
        }
        return this._owner.getMap();
    }

    /**
     * Show the UI Component, if it is a global single one, it will close previous one.
     * @param {Coordinate} [coordinate=null] - coordinate to show, default is owner's center
     * @return {ui.UIComponent} this
     * @fires ui.UIComponent#showstart
     * @fires ui.UIComponent#showend
     */
    show(coordinate) {
        const map = this.getMap();
        if (!map) {
            return this;
        }
        coordinate = coordinate || this._coordinate || this._owner.getCenter();

        const visible = this.isVisible();

        /**
         * showstart event.
         *
         * @event ui.UIComponent#showstart
         * @type {Object}
         * @property {String} type - showstart
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('showstart');
        const container = this._getUIContainer();
        this._coordinate = coordinate;
        this._removePrevDOM();
        const dom = this.__uiDOM = this.buildOn(map);

        if (!dom) {
            /**
             * showend event.
             *
             * @event ui.UIComponent#showend
             * @type {Object}
             * @property {String} type - showend
             * @property {ui.UIComponent} target - UIComponent
             */
            this.fire('showend');
            return this;
        }

        this._measureSize(dom);

        if (this._singleton()) {
            map[this._uiDomKey()] = dom;
        }

        this._setPosition();

        dom.style[TRANSITION] = null;

        container.appendChild(dom);

        const anim = this._getAnimation();

        if (visible) {
            anim.ok = false;
        }

        if (anim.ok) {
            if (anim.fade) {
                dom.style.opacity = 0;
            }
            if (anim.scale) {
                if (this.getTransformOrigin) {
                    const origin = this.getTransformOrigin();
                    dom.style[TRANSFORMORIGIN] = origin.x + 'px ' + origin.y + 'px';
                }
                dom.style[TRANSFORM] = toCSSTranslate(this._pos) + ' scale(0)';
            }
        }

        dom.style.display = '';

        if (this.options['eventsToStop']) {
            on(dom, this.options['eventsToStop'], stopPropagation);
        }

        //autoPan
        if (this.options['autoPan']) {
            this._autoPan();
        }

        const transition = anim.transition;
        if (anim.ok && transition) {
            /* eslint-disable no-unused-expressions */
            // trigger transition
            dom.offsetHeight;
            /* eslint-enable no-unused-expressions */
            if (transition) {
                dom.style[TRANSITION] = transition;
            }
            if (anim.fade) {
                dom.style.opacity = 1;
            }
            if (anim.scale) {
                dom.style[TRANSFORM] = toCSSTranslate(this._pos) + ' scale(1)';
            }
        }

        this.fire('showend');
        return this;
    }

    /**
     * Hide the UI Component.
     * @return {ui.UIComponent} this
     * @fires ui.UIComponent#hide
     */
    hide() {
        if (!this.getDOM() || !this.getMap()) {
            return this;
        }

        const anim = this._getAnimation(),
            dom = this.getDOM();
        if (!this.options['animationOnHide']) {
            anim.ok = false;
        }
        if (!anim.ok) {
            dom.style.display = 'none';
        } else {
            /* eslint-disable no-unused-expressions */
            dom.offsetHeight;
            /* eslint-enable no-unused-expressions */
            dom.style[TRANSITION] = anim.transition;
            setTimeout(() => {
                dom.style.display = 'none';
            }, this.options['animationDuration']);
        }
        if (anim.fade) {
            dom.style.opacity = 0;
        }
        if (anim.scale) {
            dom.style[TRANSFORM] = toCSSTranslate(this._pos) + ' scale(0)';
        }

        /**
         * hide event.
         *
         * @event ui.UIComponent#hide
         * @type {Object}
         * @property {String} type - hide
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('hide');
        return this;
    }

    /**
     * Decide whether the ui component is open
     * @returns {Boolean} true|false
     */
    isVisible() {
        const dom = this.getDOM();
        return this.getMap() && dom && dom.parentNode && dom.style.display !== 'none';
    }

    /**
     * Remove the UI Component
     * @return {ui.UIComponent} this
     * @fires ui.UIComponent#hide
     * @fires ui.UIComponent#remove
     */
    remove() {
        if (!this._owner) {
            return this;
        }
        this.hide();
        this._switchEvents('off');
        if (this.onRemove) {
            this.onRemove();
        }
        if (!this._singleton() && this.__uiDOM) {
            this._removePrevDOM();
        }
        delete this._owner;
        /**
         * remove event.
         *
         * @event ui.UIComponent#remove
         * @type {Object}
         * @property {String} type - remove
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('remove');
        return this;
    }

    /**
     * Get pixel size of the UI Component.
     * @return {Size} size
     */
    getSize() {
        if (this._size) {
            return this._size.copy();
        } else {
            return null;
        }
    }

    getOwner() {
        return this._owner;
    }

    getDOM() {
        return this.__uiDOM;
    }

    getPosition() {
        if (!this.getMap()) {
            return null;
        }
        const p = this._getViewPoint()._round();
        if (this.getOffset) {
            const o = this.getOffset()._round();
            if (o) {
                p._add(o);
            }
        }
        return p;
    }

    _getAnimation() {
        const anim = {
            'fade': false,
            'scale': false
        };
        const animations = this.options['animation'] ? this.options['animation'].split(',') : [];
        for (let i = 0; i < animations.length; i++) {
            const trimed = trim(animations[i]);
            if (trimed === 'fade') {
                anim.fade = true;
            } else if (trimed === 'scale') {
                anim.scale = true;
            }
        }
        let transition = null;
        if (anim.fade) {
            transition = 'opacity ' + this.options['animationDuration'] + 'ms';
        }
        if (anim.scale) {
            transition = transition ? transition + ',' : '';
            transition += TRANSFORM + ' ' + this.options['animationDuration'] + 'ms';
        }
        anim.transition = transition;
        anim.ok = (transition !== null);
        return anim;
    }

    _getViewPoint() {
        return this.getMap().coordToViewPoint(this._coordinate)
            ._add(this.options['dx'], this.options['dy']);
    }

    _autoPan() {
        const map = this.getMap(),
            dom = this.getDOM();
        if (map.isMoving()) {
            return;
        }
        const point = this._pos;
        const mapSize = map.getSize(),
            mapWidth = mapSize['width'],
            mapHeight = mapSize['height'];

        const containerPoint = map.viewPointToContainerPoint(point);
        const clientWidth = parseInt(dom.clientWidth),
            clientHeight = parseInt(dom.clientHeight);
        let left = 0,
            top = 0;
        if ((containerPoint.x) < 0) {
            left = -(containerPoint.x - clientWidth / 2);
        } else if ((containerPoint.x + clientWidth - 35) > mapWidth) {
            left = (mapWidth - (containerPoint.x + clientWidth * 3 / 2));
        }
        if (containerPoint.y < 0) {
            top = -containerPoint.y + 50;
        } else if (containerPoint.y > mapHeight) {
            top = (mapHeight - containerPoint.y - clientHeight) - 30;
        }
        if (top !== 0 || left !== 0) {
            map.panBy(new Point(left, top), { 'duration' : this.options['autoPanDuration'] });
        }
    }

    /**
     * Measure dom's size
     * @param  {HTMLElement} dom - element to measure
     * @return {Size} size
     * @private
     */
    _measureSize(dom) {
        const container = this._getUIContainer();
        dom.style.position = 'absolute';
        dom.style.left = -99999 + 'px';
        dom.style.top = -99999 + 'px';
        dom.style.display = '';
        container.appendChild(dom);
        this._size = new Size(dom.clientWidth, dom.clientHeight);
        dom.style.display = 'none';
        dom.style.left = '0px';
        dom.style.top = '0px';
        return this._size;
    }

    /**
     * Remove previous UI DOM if it has.
     *
     * @private
     */
    _removePrevDOM() {
        if (this.onDomRemove) {
            this.onDomRemove();
        }
        const eventsToStop = this.options['eventsToStop'];
        if (this._singleton()) {
            const map = this.getMap(),
                key = this._uiDomKey();
            if (map[key]) {
                if (eventsToStop) {
                    off(map[key], eventsToStop, stopPropagation);
                }
                removeDomNode(map[key]);
                delete map[key];
            }
            delete this.__uiDOM;
        } else if (this.__uiDOM) {
            if (eventsToStop) {
                off(this.__uiDOM, eventsToStop, stopPropagation);
            }
            removeDomNode(this.__uiDOM);
            delete this.__uiDOM;
        }
    }

    /**
     * generate the cache key to store the singletong UI DOM
     * @private
     * @return {String} cache key
     */
    _uiDomKey() {
        return '__ui_' + this._getClassName();
    }

    _singleton() {
        return this.options['single'];
    }

    _getUIContainer() {
        return this.getMap()._panels['ui'];
    }

    _getClassName() {
        return 'UIComponent';
    }

    _switchEvents(to) {
        const events = this._getDefaultEvents();
        if (this.getEvents) {
            extend(events, this.getEvents());
        }
        if (events) {
            const map = this.getMap();
            if (map) {
                for (const p in events) {
                    if (events.hasOwnProperty(p)) {
                        map[to](p, events[p], this);
                    }
                }
            }
        }
        const ownerEvents = this._getOwnerEvents();
        if (this._owner) {
            for (const p in ownerEvents) {
                if (ownerEvents.hasOwnProperty(p)) {
                    this._owner[to](p, ownerEvents[p], this);
                }
            }
        }
    }

    _getDefaultEvents() {
        return {
            'zooming rotate pitch': this.onEvent,
            'zoomend' : this.onZoomEnd,
            'moving': this.onMoving
        };
    }

    _getOwnerEvents() {
        const events = {};
        if (this._owner && (this._owner instanceof Geometry)) {
            events.positionchange = this.onGeometryPositionChange;
        }
        if (this.getOwnerEvents) {
            extend(events, this.getOwnerEvents());
        }
        return events;
    }

    onGeometryPositionChange(param) {
        if (this._owner && this.isVisible()) {
            this.show(param['target'].getCenter());
        }
    }

    onMoving() {
        if (this.isVisible() && this.getMap().isTransforming()) {
            this._updatePosition();
        }
    }

    onEvent() {
        if (this.isVisible()) {
            this._updatePosition();
        }
    }

    onZoomEnd() {
        if (this.isVisible()) {
            // when zoomend, map container is reset, position should be updated in current frame
            this._setPosition();
        }
    }

    _updatePosition() {
        // update position in the next frame to sync with layers
        const renderer = this.getMap()._getRenderer();
        renderer.callInNextFrame(this._setPosition.bind(this));
    }

    _setPosition() {
        const dom = this.getDOM(),
            p = this.getPosition();
        this._pos = p;
        dom.style[TRANSITION] = null;
        dom.style[TRANSFORM] = toCSSTranslate(p) + ' scale(1)';
    }
}

UIComponent.mergeOptions(options);

function toCSSTranslate(p) {
    if (!p) {
        return '';
    }
    if (Browser.any3d) {
        return 'translate3d(' + p.x + 'px,' + p.y + 'px, 0px)';
    } else {
        return 'translate(' + p.x + 'px,' + p.y + 'px)';
    }
}

export default UIComponent;
<commit_msg>fix infowindow's map events listening<commit_after>import { extend } from 'core/util';
import { trim } from 'core/util/strings';
import {
    on,
    off,
    removeDomNode,
    stopPropagation,
    TRANSFORM,
    TRANSFORMORIGIN,
    TRANSITION
} from 'core/util/dom';
import Browser from 'core/Browser';
import Class from 'core/Class';
import Eventable from 'core/Eventable';
import Point from 'geo/Point';
import Size from 'geo/Size';
import Geometry from 'geometry/Geometry';

/**
 * @property {Object} options
 * @property {Boolean} [options.eventsToStop='mousedown dblclick']  - UI's dom events to stop propagation.
 * @property {Number}  [options.dx=0]     - pixel offset on x axis
 * @property {Number}  [options.dy=0]     - pixel offset on y axis
 * @property {Boolean} [options.autoPan=false]  - set it to false if you don't want the map to do panning animation to fit the opened UI.
 * @property {Boolean} [options.autoPanDuration=600]    - duration for auto panning animation.
 * @property {Boolean} [options.single=true]    - whether the UI is a global single one, only one UI will be shown at the same time if set to true.
 * @property {Boolean} [options.animation=null]         - fade | scale | fade,scale, add animation effect when showing and hiding.
 * @property {Number}  [options.animationDuration=300]  - animation duration, in milliseconds.
 * @memberOf ui.UIComponent
 * @instance
 */
const options = {
    'eventsToStop': 'mousedown dblclick',
    'dx': 0,
    'dy': 0,
    'autoPan': false,
    'autoPanDuration' : 600,
    'single': true,
    'animation': 'scale',
    'animationOnHide': true,
    'animationDuration': 500
};

/**
 * @classdesc
 * Base class for all the UI component classes, a UI component is a HTMLElement positioned with geographic coordinate.

 * It is abstract and not intended to be instantiated.
 *
 * @category ui
 * @abstract
 * @mixes Eventable
 * @memberOf ui
 * @extends Class
 */
class UIComponent extends Eventable(Class) {

    /**
     *  Some instance methods subclasses needs to implement:

     *

     * 1. Optional, returns the Dom element's position offset

     * function getOffset : Point

     *

     * 2. Method to create UI's Dom element

     * function buildOn : HTMLElement

     *

     * 3 Optional, to provide an event map to register event listeners.

     * function getEvents : void

     * 4 Optional, a callback when dom is removed.

     * function onDomRemove : void

     * 5 Optional, a callback when UI Component is removed.

     * function onRemove : void

     * @param  {Object} options configuration options
     */
    constructor(options) {
        super(options);
    }

    /**
     * Adds the UI Component to a geometry or a map
     * @param {Geometry|Map} owner - geometry or map to addto.
     * @returns {ui.UIComponent} this
     * @fires ui.UIComponent#add
     */
    addTo(owner) {
        this._owner = owner;
        // first time
        this._switchEvents('on');
        if (this.onAdd) {
            this.onAdd();
        }
        /**
         * add event.
         *
         * @event ui.UIComponent#add
         * @type {Object}
         * @property {String} type - add
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('add');
        return this;
    }

    /**
     * Get the map it added to
     * @return {Map} map instance
     * @override
     */
    getMap() {
        if (!this._owner) {
            return null;
        }
        // is a map
        if (this._owner.getBaseLayer) {
            return this._owner;
        }
        return this._owner.getMap();
    }

    /**
     * Show the UI Component, if it is a global single one, it will close previous one.
     * @param {Coordinate} [coordinate=null] - coordinate to show, default is owner's center
     * @return {ui.UIComponent} this
     * @fires ui.UIComponent#showstart
     * @fires ui.UIComponent#showend
     */
    show(coordinate) {
        const map = this.getMap();
        if (!map) {
            return this;
        }

        if (!this._mapEventsOn) {
            this._switchMapEvents('on');
        }

        coordinate = coordinate || this._coordinate || this._owner.getCenter();

        const visible = this.isVisible();

        /**
         * showstart event.
         *
         * @event ui.UIComponent#showstart
         * @type {Object}
         * @property {String} type - showstart
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('showstart');
        const container = this._getUIContainer();
        this._coordinate = coordinate;
        this._removePrevDOM();
        const dom = this.__uiDOM = this.buildOn(map);

        if (!dom) {
            /**
             * showend event.
             *
             * @event ui.UIComponent#showend
             * @type {Object}
             * @property {String} type - showend
             * @property {ui.UIComponent} target - UIComponent
             */
            this.fire('showend');
            return this;
        }

        this._measureSize(dom);

        if (this._singleton()) {
            map[this._uiDomKey()] = dom;
        }

        this._setPosition();

        dom.style[TRANSITION] = null;

        container.appendChild(dom);

        const anim = this._getAnimation();

        if (visible) {
            anim.ok = false;
        }

        if (anim.ok) {
            if (anim.fade) {
                dom.style.opacity = 0;
            }
            if (anim.scale) {
                if (this.getTransformOrigin) {
                    const origin = this.getTransformOrigin();
                    dom.style[TRANSFORMORIGIN] = origin.x + 'px ' + origin.y + 'px';
                }
                dom.style[TRANSFORM] = toCSSTranslate(this._pos) + ' scale(0)';
            }
        }

        dom.style.display = '';

        if (this.options['eventsToStop']) {
            on(dom, this.options['eventsToStop'], stopPropagation);
        }

        //autoPan
        if (this.options['autoPan']) {
            this._autoPan();
        }

        const transition = anim.transition;
        if (anim.ok && transition) {
            /* eslint-disable no-unused-expressions */
            // trigger transition
            dom.offsetHeight;
            /* eslint-enable no-unused-expressions */
            if (transition) {
                dom.style[TRANSITION] = transition;
            }
            if (anim.fade) {
                dom.style.opacity = 1;
            }
            if (anim.scale) {
                dom.style[TRANSFORM] = toCSSTranslate(this._pos) + ' scale(1)';
            }
        }

        this.fire('showend');
        return this;
    }

    /**
     * Hide the UI Component.
     * @return {ui.UIComponent} this
     * @fires ui.UIComponent#hide
     */
    hide() {
        if (!this.getDOM() || !this.getMap()) {
            return this;
        }

        const anim = this._getAnimation(),
            dom = this.getDOM();
        if (!this.options['animationOnHide']) {
            anim.ok = false;
        }
        if (!anim.ok) {
            dom.style.display = 'none';
        } else {
            /* eslint-disable no-unused-expressions */
            dom.offsetHeight;
            /* eslint-enable no-unused-expressions */
            dom.style[TRANSITION] = anim.transition;
            setTimeout(() => {
                dom.style.display = 'none';
            }, this.options['animationDuration']);
        }
        if (anim.fade) {
            dom.style.opacity = 0;
        }
        if (anim.scale) {
            dom.style[TRANSFORM] = toCSSTranslate(this._pos) + ' scale(0)';
        }

        /**
         * hide event.
         *
         * @event ui.UIComponent#hide
         * @type {Object}
         * @property {String} type - hide
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('hide');
        return this;
    }

    /**
     * Decide whether the ui component is open
     * @returns {Boolean} true|false
     */
    isVisible() {
        const dom = this.getDOM();
        return this.getMap() && dom && dom.parentNode && dom.style.display !== 'none';
    }

    /**
     * Remove the UI Component
     * @return {ui.UIComponent} this
     * @fires ui.UIComponent#hide
     * @fires ui.UIComponent#remove
     */
    remove() {
        delete this._mapEventsOn;
        if (!this._owner) {
            return this;
        }
        this.hide();
        this._switchEvents('off');
        if (this.onRemove) {
            this.onRemove();
        }
        if (!this._singleton() && this.__uiDOM) {
            this._removePrevDOM();
        }
        delete this._owner;
        /**
         * remove event.
         *
         * @event ui.UIComponent#remove
         * @type {Object}
         * @property {String} type - remove
         * @property {ui.UIComponent} target - UIComponent
         */
        this.fire('remove');
        return this;
    }

    /**
     * Get pixel size of the UI Component.
     * @return {Size} size
     */
    getSize() {
        if (this._size) {
            return this._size.copy();
        } else {
            return null;
        }
    }

    getOwner() {
        return this._owner;
    }

    getDOM() {
        return this.__uiDOM;
    }

    getPosition() {
        if (!this.getMap()) {
            return null;
        }
        const p = this._getViewPoint()._round();
        if (this.getOffset) {
            const o = this.getOffset()._round();
            if (o) {
                p._add(o);
            }
        }
        return p;
    }

    _getAnimation() {
        const anim = {
            'fade': false,
            'scale': false
        };
        const animations = this.options['animation'] ? this.options['animation'].split(',') : [];
        for (let i = 0; i < animations.length; i++) {
            const trimed = trim(animations[i]);
            if (trimed === 'fade') {
                anim.fade = true;
            } else if (trimed === 'scale') {
                anim.scale = true;
            }
        }
        let transition = null;
        if (anim.fade) {
            transition = 'opacity ' + this.options['animationDuration'] + 'ms';
        }
        if (anim.scale) {
            transition = transition ? transition + ',' : '';
            transition += TRANSFORM + ' ' + this.options['animationDuration'] + 'ms';
        }
        anim.transition = transition;
        anim.ok = (transition !== null);
        return anim;
    }

    _getViewPoint() {
        return this.getMap().coordToViewPoint(this._coordinate)
            ._add(this.options['dx'], this.options['dy']);
    }

    _autoPan() {
        const map = this.getMap(),
            dom = this.getDOM();
        if (map.isMoving()) {
            return;
        }
        const point = this._pos;
        const mapSize = map.getSize(),
            mapWidth = mapSize['width'],
            mapHeight = mapSize['height'];

        const containerPoint = map.viewPointToContainerPoint(point);
        const clientWidth = parseInt(dom.clientWidth),
            clientHeight = parseInt(dom.clientHeight);
        let left = 0,
            top = 0;
        if ((containerPoint.x) < 0) {
            left = -(containerPoint.x - clientWidth / 2);
        } else if ((containerPoint.x + clientWidth - 35) > mapWidth) {
            left = (mapWidth - (containerPoint.x + clientWidth * 3 / 2));
        }
        if (containerPoint.y < 0) {
            top = -containerPoint.y + 50;
        } else if (containerPoint.y > mapHeight) {
            top = (mapHeight - containerPoint.y - clientHeight) - 30;
        }
        if (top !== 0 || left !== 0) {
            map.panBy(new Point(left, top), { 'duration' : this.options['autoPanDuration'] });
        }
    }

    /**
     * Measure dom's size
     * @param  {HTMLElement} dom - element to measure
     * @return {Size} size
     * @private
     */
    _measureSize(dom) {
        const container = this._getUIContainer();
        dom.style.position = 'absolute';
        dom.style.left = -99999 + 'px';
        dom.style.top = -99999 + 'px';
        dom.style.display = '';
        container.appendChild(dom);
        this._size = new Size(dom.clientWidth, dom.clientHeight);
        dom.style.display = 'none';
        dom.style.left = '0px';
        dom.style.top = '0px';
        return this._size;
    }

    /**
     * Remove previous UI DOM if it has.
     *
     * @private
     */
    _removePrevDOM() {
        if (this.onDomRemove) {
            this.onDomRemove();
        }
        const eventsToStop = this.options['eventsToStop'];
        if (this._singleton()) {
            const map = this.getMap(),
                key = this._uiDomKey();
            if (map[key]) {
                if (eventsToStop) {
                    off(map[key], eventsToStop, stopPropagation);
                }
                removeDomNode(map[key]);
                delete map[key];
            }
            delete this.__uiDOM;
        } else if (this.__uiDOM) {
            if (eventsToStop) {
                off(this.__uiDOM, eventsToStop, stopPropagation);
            }
            removeDomNode(this.__uiDOM);
            delete this.__uiDOM;
        }
    }

    /**
     * generate the cache key to store the singletong UI DOM
     * @private
     * @return {String} cache key
     */
    _uiDomKey() {
        return '__ui_' + this._getClassName();
    }

    _singleton() {
        return this.options['single'];
    }

    _getUIContainer() {
        return this.getMap()._panels['ui'];
    }

    _getClassName() {
        return 'UIComponent';
    }

    _switchMapEvents(to) {
        const map = this.getMap();
        if (!map) {
            return;
        }
        this._mapEventsOn = (to === 'on');
        const events = this._getDefaultEvents();
        if (this.getEvents) {
            extend(events, this.getEvents());
        }
        if (events) {
            for (const p in events) {
                if (events.hasOwnProperty(p)) {
                    map[to](p, events[p], this);
                }
            }
        }
    }

    _switchEvents(to) {
        this._switchMapEvents(to);
        const ownerEvents = this._getOwnerEvents();
        if (this._owner) {
            for (const p in ownerEvents) {
                if (ownerEvents.hasOwnProperty(p)) {
                    this._owner[to](p, ownerEvents[p], this);
                }
            }
        }
    }

    _getDefaultEvents() {
        return {
            'zooming rotate pitch': this.onEvent,
            'zoomend' : this.onZoomEnd,
            'moving': this.onMoving
        };
    }

    _getOwnerEvents() {
        const events = {};
        if (this._owner && (this._owner instanceof Geometry)) {
            events.positionchange = this.onGeometryPositionChange;
        }
        if (this.getOwnerEvents) {
            extend(events, this.getOwnerEvents());
        }
        return events;
    }

    onGeometryPositionChange(param) {
        if (this._owner && this.isVisible()) {
            this.show(param['target'].getCenter());
        }
    }

    onMoving() {
        if (this.isVisible() && this.getMap().isTransforming()) {
            this._updatePosition();
        }
    }

    onEvent() {
        if (this.isVisible()) {
            this._updatePosition();
        }
    }

    onZoomEnd() {
        if (this.isVisible()) {
            // when zoomend, map container is reset, position should be updated in current frame
            this._setPosition();
        }
    }

    _updatePosition() {
        // update position in the next frame to sync with layers
        const renderer = this.getMap()._getRenderer();
        renderer.callInNextFrame(this._setPosition.bind(this));
    }

    _setPosition() {
        const dom = this.getDOM(),
            p = this.getPosition();
        this._pos = p;
        dom.style[TRANSITION] = null;
        dom.style[TRANSFORM] = toCSSTranslate(p) + ' scale(1)';
    }
}

UIComponent.mergeOptions(options);

function toCSSTranslate(p) {
    if (!p) {
        return '';
    }
    if (Browser.any3d) {
        return 'translate3d(' + p.x + 'px,' + p.y + 'px, 0px)';
    } else {
        return 'translate(' + p.x + 'px,' + p.y + 'px)';
    }
}

export default UIComponent;
<|endoftext|>


<commit_before>import * as I from 'immutable';

import * as surface   from '../graphics/surface';
import * as delaney   from '../dsymbols/delaney';
import * as delaney3d from '../dsymbols/delaney3d';
import * as util      from '../common/util';

const processedSolid = (t0, subDLevel, timers) => {
  surface.useTimers(timers);

  timers && timers.start('adding flattened center faces');
  const t1 = surface.withFlattenedCenterFaces(t0);
  timers && timers.stop('adding flattened center faces');

  timers && timers.start('subdividing the faces');
  const t2 = I.Range(0, subDLevel).reduce(s => surface.subD(s), t1);
  timers && timers.stop('subdividing the faces');

  timers && timers.start('insetting');
  const t3 = surface.insetAt(t2, 0.01, t2.isFixed);
  timers && timers.stop('insetting');

  timers && timers.start('beveling');
  const t4 = surface.beveledAt(t3, 0.005, t2.isFixed);
  timers && timers.stop('beveling');

  surface.useTimers(null);

  return surface.standardized(t4);
};

const handlers = {
  processSolid({ pos, faces, isFixed, subDLevel }) {
    const surfIn = {
      pos    : I.List(pos),
      faces  : I.fromJS(faces),
      isFixed: I.fromJS(isFixed)
    };

    const timer = util.timer();
    const timers = util.timers();

    const surfOut = processedSolid(surfIn, subDLevel, timers);

    console.log(`${Math.round(timer())} msec in total to process the surfaces`);
    console.log(`  surface processing details:`);
    console.log(`${JSON.stringify(timers.current(), null, 2)}`);

    return {
      pos    : surfOut.pos.toJS(),
      faces  : surfOut.faces.toJS(),
      isFixed: surfOut.isFixed.toJS()
    };
  },

  processSolids(solids) {
    return solids.map(this.processSolid);
  },

  dsCover(dsTxt) {
    const ds = delaney.parse(dsTxt);

    const t = util.timer();
    const cov = delaney3d.pseudoToroidalCover(ds);
    console.log(`${Math.round(t())} msec in total to compute the cover`);

    return `${cov}`;
  }
};

onmessage = event => {
  const { id, input: { cmd, val } } = event.data;
  postMessage({ id, output: handlers[cmd](val), ok: true });
};
<commit_msg>reduce timer output for surface processing<commit_after>import * as I from 'immutable';

import * as surface   from '../graphics/surface';
import * as delaney   from '../dsymbols/delaney';
import * as delaney3d from '../dsymbols/delaney3d';
import * as util      from '../common/util';

const processedSolid = (t0, subDLevel, timers) => {
  surface.useTimers(timers);

  timers && timers.start('adding flattened center faces');
  const t1 = surface.withFlattenedCenterFaces(t0);
  timers && timers.stop('adding flattened center faces');

  timers && timers.start('subdividing the faces');
  const t2 = I.Range(0, subDLevel).reduce(s => surface.subD(s), t1);
  timers && timers.stop('subdividing the faces');

  timers && timers.start('insetting');
  const t3 = surface.insetAt(t2, 0.01, t2.isFixed);
  timers && timers.stop('insetting');

  timers && timers.start('beveling');
  const t4 = surface.beveledAt(t3, 0.005, t2.isFixed);
  timers && timers.stop('beveling');

  surface.useTimers(null);

  return surface.standardized(t4);
};

const handlers = {
  processSolid({ pos, faces, isFixed, subDLevel }) {
    const surfIn = {
      pos    : I.List(pos),
      faces  : I.fromJS(faces),
      isFixed: I.fromJS(isFixed)
    };

    const surfOut = processedSolid(surfIn, subDLevel);

    return {
      pos    : surfOut.pos.toJS(),
      faces  : surfOut.faces.toJS(),
      isFixed: surfOut.isFixed.toJS()
    };
  },

  processSolids(solidsIn) {
    const t = util.timer();
    const solidsOut = solidsIn.map(this.processSolid);
    console.log(`${Math.round(t())} msec in total to process the surfaces`);

    return solidsOut;
  },

  dsCover(dsTxt) {
    const ds = delaney.parse(dsTxt);

    const t = util.timer();
    const cov = delaney3d.pseudoToroidalCover(ds);
    console.log(`${Math.round(t())} msec in total to compute the cover`);

    return `${cov}`;
  }
};

onmessage = event => {
  const { id, input: { cmd, val } } = event.data;
  postMessage({ id, output: handlers[cmd](val), ok: true });
};
<|endoftext|>


<commit_before>import fs from 'fs'
import path from 'path'
import mkdirp from 'mkdirp'
import after from 'lodash/function/after'
import each from 'lodash/collection/each'
import partial from 'lodash/function/partial'
import {parallel} from 'async'
import request from 'request'
import debug from './debug'

const debugApi = debug('api')
const debugJson = debug('json')
const debugMedia = debug('media')

const shouldWrite = ({debug, filepath, overwrite}, no, yes) => {
  fs.exists(filepath, (exists) => {
    if (exists && !overwrite) {
      debug(`Exists, skipping ${filepath}`)
      no()
    } else if (exists && overwrite) {
      debug(`Exists, overwriting ${filepath}`)
      yes()
    } else {
      debug(`Does not exist, writing ${filepath}`)
      yes()
    }
  })
}

export const saveJson = ({ig, jsonDir, refresh, full}) => (json, saveDone) => {
  const id = json.id
  const filepath = jsonDir(`${id}.json`)

  const writeIfNeeded = partial(shouldWrite, {debug: debugJson, filepath, overwrite: refresh}, saveDone)
  const writeFile = (data) => fs.writeFile(filepath, JSON.stringify(data), {encoding: 'utf8'}, saveDone)

  const fetchForPost = (fetch) => (cb) => ig[fetch](id, (err, res, remaining) => {
    debugApi(`API calls left ${remaining}`)
    if (err) {
      debugApi(`${fetch} API error ${err}`)
      return cb(err)
    }
    debugJson(`${id} ${fetch} ${res.length}`)
    cb(null, res)
  })

  writeIfNeeded(() => {
    if (full) {
      // Full means we fetch likes and comments separately and add those
      // to the json payload that gets saved
      parallel({
        likes: fetchForPost('likes'),
        comments: fetchForPost('comments')
      }, (err, {likes, comments}) => {
        if (err) return saveDone(err)
        json.likes.data = likes
        json.comments.data = comments
        writeFile(json)
      })
    } else {
      writeFile(json)
    }
  })
}

export const saveMedia = ({mediaDir}) => (url, saveDone) => {
  // The Instagram media files get saved to a location on disk that matches the
  // urls domain+path, so we need to make that directory and then save the file
  const stripped = url.replace(/^https?:\/\//, '/')
  const dirname = mediaDir(path.dirname(stripped))
  const filepath = path.join(dirname, path.basename(stripped))

  // An Instagram media at a url should never change so we shouldn't ever
  // need to download it more than once
  const writeIfNeeded = partial(shouldWrite, {debug: debugMedia, filepath, overwrite: false}, saveDone)

  writeIfNeeded(() => {
    mkdirp(dirname, (err) => {
      if (err) return saveDone(err)
      request(url).pipe(fs.createWriteStream(filepath)).on('close', saveDone)
    })
  })
}

export const fetchAndSave = ({jsonQueue, mediaQueue}, cb) => {
  let COUNT = 0

  // The callback passed to the function will be executed once
  // both json and media queues have been drained
  const onDrain = after(2, cb)
  jsonQueue.drain = () => {
    debugJson('queue drain')
    onDrain()
  }
  mediaQueue.drain = () => {
    debugMedia('queue drain')
    onDrain()
  }

  const fetchMedia = (err, medias, pagination, remaining) => {
    debugApi(`API calls left ${remaining}`)

    if (err) {
      console.log(err.error_type)
      if (err.error_type === 'APINotAllowedError') {
        debugApi(`Its possible the user's account you are trying to download is private`)
      }
      debugApi(`API error ${err}`)
    } else if (medias && medias.length) {
      COUNT += medias.length
      debugApi(`Fetched media ${medias.length}`)
      debugApi(`Fetched total ${COUNT}`)
      medias.forEach((media) => {
        jsonQueue.push(media)
        each(media.images, (img) => mediaQueue.push(img.url))
        each(media.videos, (video) => mediaQueue.push(video.url))
      })
    } else if (medias.length === 0 && COUNT === 0 && !pagination.next) {
      debugApi('No media')
      cb()
    }

    if (pagination) {
      debugApi(`Has next page ${!!pagination.next}`)
      pagination.next && pagination.next(fetchMedia)
    }
  }

  return fetchMedia
}
<commit_msg>removing console.log<commit_after>import fs from 'fs'
import path from 'path'
import mkdirp from 'mkdirp'
import after from 'lodash/function/after'
import each from 'lodash/collection/each'
import partial from 'lodash/function/partial'
import {parallel} from 'async'
import request from 'request'
import debug from './debug'

const debugApi = debug('api')
const debugJson = debug('json')
const debugMedia = debug('media')

const shouldWrite = ({debug, filepath, overwrite}, no, yes) => {
  fs.exists(filepath, (exists) => {
    if (exists && !overwrite) {
      debug(`Exists, skipping ${filepath}`)
      no()
    } else if (exists && overwrite) {
      debug(`Exists, overwriting ${filepath}`)
      yes()
    } else {
      debug(`Does not exist, writing ${filepath}`)
      yes()
    }
  })
}

export const saveJson = ({ig, jsonDir, refresh, full}) => (json, saveDone) => {
  const id = json.id
  const filepath = jsonDir(`${id}.json`)

  const writeIfNeeded = partial(shouldWrite, {debug: debugJson, filepath, overwrite: refresh}, saveDone)
  const writeFile = (data) => fs.writeFile(filepath, JSON.stringify(data), {encoding: 'utf8'}, saveDone)

  const fetchForPost = (fetch) => (cb) => ig[fetch](id, (err, res, remaining) => {
    debugApi(`API calls left ${remaining}`)
    if (err) {
      debugApi(`${fetch} API error ${err}`)
      return cb(err)
    }
    debugJson(`${id} ${fetch} ${res.length}`)
    cb(null, res)
  })

  writeIfNeeded(() => {
    if (full) {
      // Full means we fetch likes and comments separately and add those
      // to the json payload that gets saved
      parallel({
        likes: fetchForPost('likes'),
        comments: fetchForPost('comments')
      }, (err, {likes, comments}) => {
        if (err) return saveDone(err)
        json.likes.data = likes
        json.comments.data = comments
        writeFile(json)
      })
    } else {
      writeFile(json)
    }
  })
}

export const saveMedia = ({mediaDir}) => (url, saveDone) => {
  // The Instagram media files get saved to a location on disk that matches the
  // urls domain+path, so we need to make that directory and then save the file
  const stripped = url.replace(/^https?:\/\//, '/')
  const dirname = mediaDir(path.dirname(stripped))
  const filepath = path.join(dirname, path.basename(stripped))

  // An Instagram media at a url should never change so we shouldn't ever
  // need to download it more than once
  const writeIfNeeded = partial(shouldWrite, {debug: debugMedia, filepath, overwrite: false}, saveDone)

  writeIfNeeded(() => {
    mkdirp(dirname, (err) => {
      if (err) return saveDone(err)
      request(url).pipe(fs.createWriteStream(filepath)).on('close', saveDone)
    })
  })
}

export const fetchAndSave = ({jsonQueue, mediaQueue}, cb) => {
  let COUNT = 0

  // The callback passed to the function will be executed once
  // both json and media queues have been drained
  const onDrain = after(2, cb)
  jsonQueue.drain = () => {
    debugJson('queue drain')
    onDrain()
  }
  mediaQueue.drain = () => {
    debugMedia('queue drain')
    onDrain()
  }

  const fetchMedia = (err, medias, pagination, remaining) => {
    debugApi(`API calls left ${remaining}`)

    if (err) {
      if (err.error_type === 'APINotAllowedError') {
        debugApi(`Its possible the user's account you are trying to download is private`)
      }
      debugApi(`API error ${err}`)
    } else if (medias && medias.length) {
      COUNT += medias.length
      debugApi(`Fetched media ${medias.length}`)
      debugApi(`Fetched total ${COUNT}`)
      medias.forEach((media) => {
        jsonQueue.push(media)
        each(media.images, (img) => mediaQueue.push(img.url))
        each(media.videos, (video) => mediaQueue.push(video.url))
      })
    } else if (medias.length === 0 && COUNT === 0 && !pagination.next) {
      debugApi('No media')
      cb()
    }

    if (pagination) {
      debugApi(`Has next page ${!!pagination.next}`)
      pagination.next && pagination.next(fetchMedia)
    }
  }

  return fetchMedia
}
<|endoftext|>


<commit_before>let webpack = require('webpack');
let webpackDevServer = require('webpack-dev-server');
let path = require('path');
let Notifier = require('./notifier');

module.exports = function(mode = 'dev', options, callback) {
	let webpackConfigPath = path.resolve(process.cwd(), `build/webpack.config.${mode}.js`);
	let webpackConfig = require(webpackConfigPath)(require);
	let compiler;

	webpackConfig.resolve.root.push( path.resolve(__dirname, '../../node_modules') );

	webpackConfig.resolveLoader = {
		root: [
			path.resolve(process.cwd(), 'node_modules'),
			path.resolve(__dirname, '../../node_modules'),
			'node_modules'
		]
	};

	if (options.notify) {
		webpackConfig.plugins.push( new Notifier() );
	}

	if (mode === 'dev') {
		let devServerEntry = path.resolve(__dirname, '../../node_modules/webpack-dev-server/client?{{host}}:{{port}}/');

		devServerEntry = devServerEntry.replace('{{host}}', `http://${options.host}`);
		devServerEntry = devServerEntry.replace('{{port}}', options.port);

		webpackConfig.entry.unshift( path.resolve(__dirname, '../../node_modules/webpack/hot/dev-server') );
		webpackConfig.entry.unshift( devServerEntry );
		webpackConfig.plugins.unshift( new webpack.HotModuleReplacementPlugin() );

		compiler = webpack(webpackConfig);

		new webpackDevServer(compiler, {
			hot: true,
			quiet: true,
			clientLogLevel: 'error'
		}).listen(options.port, options.host);
	} else {
		compiler = webpack(webpackConfig);

		compiler.run(() => {});
	}

	compiler.plugin('done', stats => {
		let details = stats.toString({
			colors: true,
			version: true,
			timings: true,
			hash: false,
			assets: true,
			children: false,
			chunks: false
		});

		if (stats.hasErrors() || stats.hasWarnings()) {
			details = stats.toString({
				colors: true,
				version: false,
				timings: false,
				hash: false,
				assets: false,
				children: false,
				chunks: false
			});
		}

		return callback(stats.hasErrors(), details);
	});
};<commit_msg>verify if webpack config has multiple entry points.<commit_after>let webpack = require('webpack');
let webpackDevServer = require('webpack-dev-server');
let path = require('path');
let _ = require('underscore');
let Notifier = require('./notifier');

module.exports = function(mode = 'dev', options, callback) {
	let webpackConfigPath = path.resolve(process.cwd(), `build/webpack.config.${mode}.js`);
	let webpackConfig = require(webpackConfigPath)(require);
	let compiler;

	webpackConfig.resolve.root.push( path.resolve(__dirname, '../../node_modules') );

	webpackConfig.resolveLoader = {
		root: [
			path.resolve(process.cwd(), 'node_modules'),
			path.resolve(__dirname, '../../node_modules'),
			'node_modules'
		]
	};

	if (options.notify) {
		webpackConfig.plugins.push( new Notifier() );
	}

	if (mode === 'dev') {
		let devServerEntry = path.resolve(__dirname, '../../node_modules/webpack-dev-server/client?{{host}}:{{port}}/');

		devServerEntry = devServerEntry.replace('{{host}}', `http://${options.host}`);
		devServerEntry = devServerEntry.replace('{{port}}', options.port);

		if (_.isArray(webpackConfig.entry)) {
			webpackConfig.entry.unshift( path.resolve(__dirname, '../../node_modules/webpack/hot/dev-server') );
			webpackConfig.entry.unshift( devServerEntry );
		} else {
			if (webpackConfig.entry.application) {
				webpackConfig.entry.application.unshift( path.resolve(__dirname, '../../node_modules/webpack/hot/dev-server') );
				webpackConfig.entry.application.unshift( devServerEntry );
			} else {
				throw new Error('When using multiple entry points, at least one must be called "application".');
			}
		}

		webpackConfig.plugins.unshift( new webpack.HotModuleReplacementPlugin() );

		compiler = webpack(webpackConfig);

		new webpackDevServer(compiler, {
			hot: true,
			quiet: true,
			clientLogLevel: 'error'
		}).listen(options.port, options.host);
	} else {
		compiler = webpack(webpackConfig);

		compiler.run(() => {});
	}

	compiler.plugin('done', stats => {
		let details = stats.toString({
			colors: true,
			version: true,
			timings: true,
			hash: false,
			assets: true,
			children: false,
			chunks: false
		});

		if (stats.hasErrors() || stats.hasWarnings()) {
			details = stats.toString({
				colors: true,
				version: false,
				timings: false,
				hash: false,
				assets: false,
				children: false,
				chunks: false
			});
		}

		return callback(stats.hasErrors(), details);
	});
};<|endoftext|>


<commit_before>// eslint-disable-next-line
import Secretin from 'secretin';

const serverURI = process.env.REACT_APP_API_SECRETIN ? process.env.REACT_APP_API_SECRETIN : 'http://devapi.secret-in.me:3000';

const secretin = new Secretin(Secretin.API.Server, serverURI);

export const Errors = {
  ...Secretin.Errors,
};

export default secretin;
<commit_msg>Remove useless eslint-disable-next-line<commit_after>import Secretin from 'secretin';

const serverURI = process.env.REACT_APP_API_SECRETIN ? process.env.REACT_APP_API_SECRETIN : 'http://devapi.secret-in.me:3000';

const secretin = new Secretin(Secretin.API.Server, serverURI);

export const Errors = {
  ...Secretin.Errors,
};

export default secretin;
<|endoftext|>