<commit_before>'use strict';

var store1 = {
  name: '1st and Pike',
  min: 23,
  max: 65,
  averageSales: 6.3,
  storeHours: ['6:00 am: ''7:00 am: ', '8:00: am ', '9:00 am: ','10:00: am ','11:00: am ','12:00: pm ', '1:00: pm ', '2:00: pm: ', '3:00: pm ', '4:00: pm ', '5:00: pm ','6:00: pm ', '7:00: pm '],
  hourlySales: [],
  randomCustomers: function() {
    return Math.round(Math.random() * (this.max - this.min) + this.min);
    },
  salesByHour: function() {
    var totalSales = 0;
      for (var i = 0; i < this.storeHours.length; i++) {
        var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
        this.hourlySales.push(cookiesPerHour);
        totalSales = (totalSales + cookiesPerHour);
        this.hourlySales.push(totalSales);
        this.storeHours.push(' Total ');
    }
  },

  toSalesPage: function() {
    for (var i = 0; i < this.hours.length; i++) {
      var pikeStore = document.getElementById('store1');
      var newLi = document.createElement('li');
      var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
      newLi.innerText = newString;
      pikeStore.appendChild(newLi);
    }
  },
};
store1.salesByHour();
store1.toSalesPage();

var store2 = {
  name:'SeaTac Airport',
  min: 3,
  max: 11,
  averageSales: 20,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
    hourlySales: [],
    randomCustomers: function() {
      Math.round(Math.random() * (this.max - this.min) + this.min);
      },
      salesByHour: function() {
        var totalSales = 0;
          for (var i = 0; i < this.hours.length; i++) {
            var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
            this.hourlySales.push(cookiesPerHour);
            totalSales = (totalSales + cookiesPerHour);
        }
      },
      toSalesPage: function() {
        for (var i = 0; i < this.hours.length; i++) {
          var pikeStore = document.getElementById('store2');
          var newLi = document.createElement('li');
          var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
          newLi.innerText = newString;
          pikeStore.appendChild(newLi);
        }
      },
    };
    store1.salesByHour();
    store1.toSalesPage();

var store3 = {
  name:'Seattle Center'
  min:11,
  max: 38,
  averageSales: 3.7,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
  hourlySales: [],
  randomCustomers: function() {
    Math.round(Math.random() * (this.max - this.min) + this.min);
    },
    salesByHour: function() {
      var totalSales = 0;
        for (var i = 0; i < this.hours.length; i++) {
          var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
          this.hourlySales.push(cookiesPerHour);
          totalSales = (totalSales + cookiesPerHour);
      }
    },
    toSalesPage: function() {
      for (var i = 0; i < this.hours.length; i++) {
        var pikeStore = document.getElementById('store3');
        var newLi = document.createElement('li');
        var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
        newLi.innerText = newString;
        pikeStore.appendChild(newLi);
      }
    },
  };
  store1.salesByHour();
  store1.toSalesPage();

var store4 = {
  name:'Capitol Hill',
  min: 20,
  max: 38,
  averageSales: 2.3,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
  hourlySales: [],
  randomCustomers: function() {
    Math.round(Math.random() * (this.max - this.min) + this.min);
    },
    salesByHour: function() {
      var totalSales = 0;
        for (var i = 0; i < this.hours.length; i++) {
          var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
          this.hourlySales.push(cookiesPerHour);
          totalSales = (totalSales + cookiesPerHour);
      }
    },
    toSalesPage: function() {
      for (var i = 0; i < this.hours.length; i++) {
        var pikeStore = document.getElementById('store4');
        var newLi = document.createElement('li');
        var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
        newLi.innerText = newString;
        pikeStore.appendChild(newLi);
      }
    },
  };
  store1.salesByHour();
  store1.toSalesPage();

var store5  = {
  name:'Alkai',
  min: 2,
  max: 16,
  averageSales: 4.6,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
  hourlySales: [],
  randomCustomers: function() {
    Math.round(Math.random() * (this.max - this.min) + this.min);
    },
    salesByHour: function() {
      var totalSales = 0;
        for (var i = 0; i < this.hours.length; i++) {
          var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
          this.hourlySales.push(cookiesPerHour);
          totalSales = (totalSales + cookiesPerHour);
      }
    },
    toSalesPage: function() {
      for (var i = 0; i < this.hours.length; i++) {
        var pikeStore = document.getElementById('store5');
        var newLi = document.createElement('li');
        var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
        newLi.innerText = newString;
        pikeStore.appendChild(newLi);
      }
    },
  };
  store1.salesByHour();
  store1.toSalesPage();

// var newE1 = document.createElement(li);
// var newText = document.createTextNode(store5.name);
// newE1.appendChild(newtext);
// var list = document.getElementsByTagName('ul')[4];
// position.appendChild(newEl);
//
// var body = document.getElementsByTagName('body')[0];
//
// for (var i = 0; i < 100; i++) {
//   var newLi = document.createElement('li');
//   var img = document.createElement('img');
//   img.setAttribute('src', 'img src=https://github.com/codefellows/seattle-201d25/commit/8c48c4225bc55d9c197a957958acaba4e0a9c4da#diff-569ca4d92443a30b113101f5e8993c47/');
//   newLi.innerText = i; // <--- if you want to change the inner text
//   newLi.appendChild(img);
//   list.appendChild(newLi);
//  }
var sotreQ ={
name: '1st and Pike',
storeHours: [0],
minCust :0,
maxCust : 0,
aveCookies: 0,
simCookies: [],
totalCookieSales: 0,
randomCustomersPer Hour: function(){
return Math.round(Math.random()) * (this.maxCust - this.minCust + 1) + this minCust);
  },
hourlySales: function(){
  this.simCookies = [];
  this.totalCookieSales =0,
  for (var i = 0 ; i < this.storeHours.length; i++) {
    var hourlyCookieSales = Math.round(this.avSales * this.randomCustomersPerHour());
      this.simCookies.push(hourlyCookieSales);
      this.totalCookieSales += hourlyCookieSales;
    }
  },

  dailySalesReport: function(){
    this.hourlySales();
    var storeLocation = document.getElementById('sales-sesction');
    var locationName = document.createElement('h2');
    locationName.innerText = this.name;
    storeLocation.appendChild(loactionName);
    var list = document.getElementById('ul');
    location.appendChild('list');

    for ()  var i = 0 ; i < this.storeHours.length; i++0) {
      var listItems = document.createElement('li');
      listItems.innerText = this.storeHours[i]+ ';'+ this.simCookies[i] + 'cookies';

      list.appendChild(listItems);
  }
  listItems.innerText = document.createElement'Total:'
+ this.totalCookieSales + 'cookies';

list.simCookies};

//generate sales
// declare a variable named list that selectd a ul to fill with data=
// document.getElementById("list")
// create a loop
// set starting and stopping point in iteration
// create and new variable for new list items
// change the inner text of new list to be the values of the store hours array
// append the new list
storeQ.hourlySales: function();
var list = document.getElementById('list');

for (var i = 0; i <storeQ.storeHours.length; i++) {
  var  listItems = document.createElement('li');
  new.innerText = i;
  listItems.innerText = storeQ.storeHours[i] + 'storeQ.simCookies[i]' + 'Cookies ';
  list.appendChild
  list.appendChild(listItems);
}
pike.dailySalesReport();
<commit_msg> Cleaned up the syntax in the code and took out the type o s that were accidents<commit_after>'use strict';

var store1 = {
  name: '1st and Pike',
  min: 23,
  max: 65,
  averageSales: 6.3,
  storeHours: ['6:00 am: ''7:00 am: ', '8:00: am ', '9:00 am: ','10:00: am ','11:00: am ','12:00: pm ', '1:00: pm ', '2:00: pm: ', '3:00: pm ', '4:00: pm ', '5:00: pm ','6:00: pm ', '7:00: pm '],
  hourlySales: [],
  randomCustomers: function() {
    return Math.round(Math.random() * (this.max - this.min) + this.min);
    },
  salesByHour: function() {
    var totalSales = 0;
      for (var i = 0; i < this.storeHours.length; i++) {
        var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
        this.hourlySales.push(cookiesPerHour);
        totalSales = (totalSales + cookiesPerHour);
        this.hourlySales.push(totalSales);
        this.storeHours.push(' Total ');
    }
  },

  toSalesPage: function() {
    for (var i = 0; i < this.hours.length; i++) {
      var pikeStore = document.getElementById('store1');
      var newLi = document.createElement('li');
      var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
      newLi.innerText = newString;
      pikeStore.appendChild(newLi);
    }
  },
};
store1.salesByHour();
store1.toSalesPage();

var store2 = {
  name:'SeaTac Airport',
  min: 3,
  max: 11,
  averageSales: 20,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
    hourlySales: [],
    randomCustomers: function() {
      Math.round(Math.random() * (this.max - this.min) + this.min);
      },
      salesByHour: function() {
        var totalSales = 0;
          for (var i = 0; i < this.hours.length; i++) {
            var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
            this.hourlySales.push(cookiesPerHour);
            totalSales = (totalSales + cookiesPerHour);
        }
      },
      toSalesPage: function() {
        for (var i = 0; i < this.hours.length; i++) {
          var pikeStore = document.getElementById('store2');
          var newLi = document.createElement('li');
          var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
          newLi.innerText = newString;
          pikeStore.appendChild(newLi);
        }
      },
    };
    store1.salesByHour();
    store1.toSalesPage();

var store3 = {
  name:'Seattle Center'
  min:11,
  max: 38,
  averageSales: 3.7,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
  hourlySales: [],
  randomCustomers: function() {
    Math.round(Math.random() * (this.max - this.min) + this.min);
    },
    salesByHour: function() {
      var totalSales = 0;
        for (var i = 0; i < this.hours.length; i++) {
          var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
          this.hourlySales.push(cookiesPerHour);
          totalSales = (totalSales + cookiesPerHour);
      }
    },
    toSalesPage: function() {
      for (var i = 0; i < this.hours.length; i++) {
        var pikeStore = document.getElementById('store3');
        var newLi = document.createElement('li');
        var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
        newLi.innerText = newString;
        pikeStore.appendChild(newLi);
      }
    },
  };
  store1.salesByHour();
  store1.toSalesPage();

var store4 = {
  name:'Capitol Hill',
  min: 20,
  max: 38,
  averageSales: 2.3,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
  hourlySales: [],
  randomCustomers: function() {
    Math.round(Math.random() * (this.max - this.min) + this.min);
    },
    salesByHour: function() {
      var totalSales = 0;
        for (var i = 0; i < this.hours.length; i++) {
          var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
          this.hourlySales.push(cookiesPerHour);
          totalSales = (totalSales + cookiesPerHour);
      }
    },
    toSalesPage: function() {
      for (var i = 0; i < this.hours.length; i++) {
        var pikeStore = document.getElementById('store4');
        var newLi = document.createElement('li');
        var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
        newLi.innerText = newString;
        pikeStore.appendChild(newLi);
      }
    },
  };
  store1.salesByHour();
  store1.toSalesPage();

var store5  = {
  name:'Alkai',
  min: 2,
  max: 16,
  averageSales: 4.6,
  hours: ['7:00 am', '8:00 am', '9:00 am','10:00 am','11:00 am','12:00 pm', '1:00 pm', '2:00 pm', '3:00 pm', '4:00 pm', '5:00 pm','6:00 pm', '7:00 pm', '8:00 pm'],
  hourlySales: [],
  randomCustomers: function() {
    Math.round(Math.random() * (this.max - this.min) + this.min);
    },
    salesByHour: function() {
      var totalSales = 0;
        for (var i = 0; i < this.hours.length; i++) {
          var cookiesPerHour = Math.round(this.averageSales * this.randomCustomers());
          this.hourlySales.push(cookiesPerHour);
          totalSales = (totalSales + cookiesPerHour);
      }
    },
    toSalesPage: function() {
      for (var i = 0; i < this.hours.length; i++) {
        var pikeStore = document.getElementById('store5');
        var newLi = document.createElement('li');
        var newString = this.hours[i] + this.hourlySales[i] + 'Cookies';
        newLi.innerText = newString;
        pikeStore.appendChild(newLi);
      }
    },
  };
  store1.salesByHour();
  store1.toSalesPage();

// var newE1 = document.createElement(li);
// var newText = document.createTextNode(store5.name);
// newE1.appendChild(newtext);
// var list = document.getElementsByTagName('ul')[4];
// position.appendChild(newEl);
//
// var body = document.getElementsByTagName('body')[0];
//
// for (var i = 0; i < 100; i++) {
//   var newLi = document.createElement('li');
//   var img = document.createElement('img');
//   img.setAttribute('src', 'img src=https://github.com/codefellows/seattle-201d25/commit/8c48c4225bc55d9c197a957958acaba4e0a9c4da#diff-569ca4d92443a30b113101f5e8993c47/');
//   newLi.innerText = i; // <--- if you want to change the inner text
//   newLi.appendChild(img);
//   list.appendChild(newLi);
//  }
var sotreQ ={
name: '1st and Pike',
storeHours: [0],
minCust :0,
maxCust : 0,
aveCookies: 0,
simCookies: [],
totalCookieSales: 0,
randomCustomersPer Hour: function(){
return Math.round(Math.random()) * (this.maxCust - this.minCust + 1) + this minCust);
  },
hourlySales: function(){
  this.simCookies = [];
  this.totalCookieSales =0,
  for (var i = 0 ; i < this.storeHours.length; i++) {
    var hourlyCookieSales = Math.round(this.avSales * this.randomCustomersPerHour());
      this.simCookies.push(hourlyCookieSales);
      this.totalCookieSales += hourlyCookieSales;
    }
  },

  dailySalesReport: function(){
    this.hourlySales();
    var storeLocation = document.getElementById('sales-report');
    var locationName = document.createElement('h2');
    locationName.innerText = this.name;
    storeLocation.appendChild(loactionName);
    var list = document.getElementById('ul');
    location.appendChild('list');

    for (var i = 0 ; i < this.storeHours.length; i++) {
      var listItems = document.createElement('li');
      listItems.innerText = this.storeHours[i]+ ':'+ this.simCookies[i] + 'cookies';
      list.appendChild(listItems);
  }
  listItems.innerText = document.createElement'Total:'
+ this.totalCookieSales + 'cookies';

list.simCookies};

//generate sales
// declare a variable named list that selectd a ul to fill with data=
// document.getElementById("list")
// create a loop
// set starting and stopping point in iteration
// create and new variable for new list items
// change the inner text of new list to be the values of the store hours array
// append the new list
storeQ.hourlySales: function();
var list = document.getElementById('list');

for (var i = 0; i <storeQ.storeHours.length; i++) {
  var  listItems = document.createElement('li');
  new.innerText = i;
  listItems.innerText = storeQ.storeHours[i] + 'storeQ.simCookies[i]' + 'Cookies ';
  list.appendChild
  list.appendChild(listItems);
}
pike.dailySalesReport();
<|endoftext|>


<commit_before>(function(){
/**
@namespace mi2JS(core)

*/

/** Very basic wrapper used for scripting(similar to JQuery and alike). Contains some useful
   methods to allow manipulation, and can be extended further if needed. For more advanced
   functionalities check {@link mi2JS(comp).Base} component and it's descendants in {@link mi2JS(comp)}.
@class NodeWrapper
@memberof mi2JS(core)
*/

/**
@name mi2JS
*/
var $ = window.mi2JS = window.mi2JS || function NodeWrapper(node, root){
	if( this instanceof $){ // called as "new mi2JS(node);"
		this.el = node instanceof String ? $.find(node, root) : node;
		if(this.el === null) throw new Error('null node or not found '+node);
	}else
		return new $(node, root);
};

/**  /^[A-Za-z]+[\w-_]*/ - defines allowed tag names when sent as parameter to find/findAll
@constant tagNameReg
@memberof mi2JS(core)
*/
$.tagNameReg = /^[A-Za-z]+[\w-_]*/;

/** return first node matching the search criteria
@function find
@memberof mi2JS(core)
@param {String} search Search pattern
@param {Element} root root node
*/
$.find = function(search, root){
	// $.nn('find',{search:search});//ASSERT

	root = root || document.body;
	if(root instanceof $) root = root.el;

	if(search.charAt(0) == '#') return root.getElementById(search.substring(1));

	if($.tagNameReg.test(search)) return root.getElementsByTagName(search)[0];

	return root.querySelector(search);
}

/** return all nodes matching the search criteria
@function findAll
@memberof mi2JS(core)
@param {String} search Search pattern
@param {Element} root root node
*/
$.findAll = function(search, root){
	// $.nn('find',{search:search});//ASSERT

	root = root || document.body;
	if(root instanceof $) root = root.el;

	if($.tagNameReg.test(search)) return root.getElementsByTagName(search);

	return root.querySelectorAll(search);
}

$.bind = function(object, func){
	// dynamic
	if(typeof func == 'string')
		return function() { object[func].apply(object, arguments); };

	// native implementation
	if(func.bind) return func.bind(object);

	// closure when native implementation not present
	return function() { func.apply(object, arguments); };
};

/**

utility for classes  -
Extends destination class with source class.

Taken over from Oliver Caldwell's blog:  Prototypical inheritance done right

{@link http://oli.me.uk/2013/06/01/prototypical-inheritance-done-right/}

@function extend
@memberof mi2JS(core)

@param {class} destination The class that should be inheriting things.
@param {class} source The parent class that should be inherited from.
@return {object} The prototype of the parent.

 */
$.extend = function(destination, source) {
	destination.prototype = Object.create(source.prototype);
	destination.prototype.constructor = destination;
	destination.superClass = source.prototype;
	return source.prototype;
};

/**
utility for classes  -
Takes prototype of the source(mixin) class and copies properties to prototype of destination class.

@function mixin
@memberof mi2JS(core)

@param {class} destination - The class that is being enhanced with the mixin
@param {class} source - The mixin class
@param {boolean} overwrite - should the existing properties be overwritten
*/
$.mixin = function(dest, source, overwrite) {
	var proto = dest.prototype, ext = source.prototype;
	for(var p in ext) if(!proto[p])	proto[p] = ext[p];
};

/** Update dest object by adding properties from another object. Copied aro only own properties
of the other object (checked by hasOwnProperty).

@function update
@memberof mi2JS(core)

@param {Object} destination - The object that is being updated
@param {Object} update - Object from which the properties are copied
*/
$.update = function(dest, update){
	if(dest && update ){
		for (var prop in update)
			if(update.hasOwnProperty(prop)) dest[prop] = update[prop];
	}
	return dest;
};

$.isArray = Array.idArray ||  function (xs) {
    return {}.toString.call(xs) === '[object Array]';
};

/** Make a shallow copy of an object.

@function copy
@memberof mi2JS(core)

@param {Object} obj - objec to copy
*/
$.copy = function(obj){
    if ($.isArray(obj)) {
        var len = obj.length;
        copy = Array(len);
        for (var i = 0; i < len; i++) {
            copy[i] = obj[i];
        }
        return copy;
    }
	return $.update({},obj);
};

/** Parse number using parseFloat, but return zero if not a number.

@function num
@memberof mi2JS(core)

@param obj - string or anything else (if parseFloat fails, zero is returned)
*/
$.num = function(str){
	var n = parseFloat(str);
	if(isNaN(n)) return 0;
	return n;
};

/** Check if passed value is empty.

null

undefined

 === 0

empty string

empty array

empty object (without any iterable properties)

@function isEmpty
@memberof mi2JS(core)

@param obj
*/
$.isEmpty = function(obj){
	if(obj === void 0 || obj === null || obj === 0) return true;
	if(obj instanceof Array || typeof obj == 'string') return obj.length == 0;
	if(typeof obj == 'object'){
		for(var p in obj) return false;
		return true;
	}
	return false;
};

$.listen = function ( obj, evt, fnc, self, useCapture ){

//	$.nn('$.listen', {obj:obj, evt:evt, fnc:fnc} );

	var listener = function(evt){
		if(typeof(fnc) == 'string') fnc = self[fnc];
		fnc.call(self || obj, $.fixEvent(evt));
	};

	if (obj.addEventListener){
		obj.addEventListener(evt,listener,useCapture === true);
		return true;
	}
	else
		return obj.attachEvent("on"+evt,listener);
};

$.fixEvent = function(evt){
	evt = evt || window.event;
	evt.stop = function() {
		if(this.preventDefault){
			this.preventDefault();
			this.stopPropagation();
		} else {
			this.returnValue = false;
		}
	};

	evt.target = evt.target || evt.srcElement;

	evt.pointerX = function() {
		return this.pageX || (this.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
	};

	evt.pointerY = function() {
		return this.pageY || (this.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
	};

	return evt;
};

}());
<commit_msg>update docs<commit_after>(function(){
/**
@namespace mi2JS(core)

*/

/** Very basic wrapper used for scripting(similar to JQuery and alike). Contains some useful
   methods to allow manipulation, and can be extended further if needed. For more advanced
   functionalities check {@link mi2JS(comp).Base} component and it's descendants in {@link mi2JS(comp)}.
@class NodeWrapper
@memberof mi2JS(core)
*/

/**
@name mi2JS
*/
var $ = window.mi2JS = window.mi2JS || function NodeWrapper(node, root){
	if( this instanceof $){ // called as "new mi2JS(node);"
		this.el = node instanceof String ? $.find(node, root) : node;
		if(this.el === null) throw new Error('null node or not found '+node);
	}else
		return new $(node, root);
};

/**  /^[A-Za-z]+[\w-_]*/ - defines allowed tag names when sent as parameter to find/findAll
@constant tagNameReg
@memberof mi2JS(core)
*/
$.tagNameReg = /^[A-Za-z]+[\w-_]*/;

/** return first node matching the search criteria
@function find
@memberof mi2JS(core)
@param {String} search Search pattern
@param {Element} root root node
*/
$.find = function(search, root){
	// $.nn('find',{search:search});//ASSERT

	root = root || document.body;
	if(root instanceof $) root = root.el;

	if(search.charAt(0) == '#') return root.getElementById(search.substring(1));

	if($.tagNameReg.test(search)) return root.getElementsByTagName(search)[0];

	return root.querySelector(search);
}

/** return all nodes matching the search criteria
@function findAll
@memberof mi2JS(core)
@param {String} search Search pattern
@param {Element} root root node
*/
$.findAll = function(search, root){
	// $.nn('find',{search:search});//ASSERT

	root = root || document.body;
	if(root instanceof $) root = root.el;

	if($.tagNameReg.test(search)) return root.getElementsByTagName(search);

	return root.querySelectorAll(search);
}

/** use the object as scope for the function (popular)
@function bind
@memberof mi2JS(core)
@param {Object} object scope for the function
@param {Element} func function
*/
$.bind = function(object, func){
	// dynamic
	if(typeof func == 'string')
		return function() { object[func].apply(object, arguments); };

	// native implementation
	if(func.bind) return func.bind(object);

	// closure when native implementation not present
	return function() { func.apply(object, arguments); };
};

/**

utility for classes  -
Extends destination class with source class.

Taken over from Oliver Caldwell's blog:  Prototypical inheritance done right

{@link http://oli.me.uk/2013/06/01/prototypical-inheritance-done-right/}

@function extend
@memberof mi2JS(core)

@param {class} destination The class that should be inheriting things.
@param {class} source The parent class that should be inherited from.
@return {object} The prototype of the parent.

 */
$.extend = function(destination, source) {
	destination.prototype = Object.create(source.prototype);
	destination.prototype.constructor = destination;
	destination.superClass = source.prototype;
	return source.prototype;
};

/**
utility for classes  -
Takes prototype of the source(mixin) class and copies properties to prototype of destination class.

@function mixin
@memberof mi2JS(core)

@param {class} destination - The class that is being enhanced with the mixin
@param {class} source - The mixin class
@param {boolean} overwrite - should the existing properties be overwritten
*/
$.mixin = function(dest, source, overwrite) {
	var proto = dest.prototype, ext = source.prototype;
	for(var p in ext) if(!proto[p])	proto[p] = ext[p];
};

/** Update dest object by adding properties from another object. Copied aro only own properties
of the other object (checked by hasOwnProperty).

@function update
@memberof mi2JS(core)

@param {Object} destination - The object that is being updated
@param {Object} update - Object from which the properties are copied
*/
$.update = function(dest, update){
	if(dest && update ){
		for (var prop in update)
			if(update.hasOwnProperty(prop)) dest[prop] = update[prop];
	}
	return dest;
};

/** Check if the passed parameter is an array
@function isArray
@memberof mi2JS(core)
@param {Object} object
*/
$.isArray = Array.isArray ||  function (xs) {
    return {}.toString.call(xs) === '[object Array]';
};

/** Make a shallow copy of an object.

@function copy
@memberof mi2JS(core)

@param {Object} obj - objec to copy
*/
$.copy = function(obj){
    if ($.isArray(obj)) {
        var len = obj.length;
        copy = Array(len);
        for (var i = 0; i < len; i++) {
            copy[i] = obj[i];
        }
        return copy;
    }
	return $.update({},obj);
};

/** Parse number using parseFloat, but return zero if not a number.

@function num
@memberof mi2JS(core)

@param obj - string or anything else (if parseFloat fails, zero is returned)
*/
$.num = function(str){
	var n = parseFloat(str);
	if(isNaN(n)) return 0;
	return n;
};

/** Check if passed value is empty.

null

undefined

 === 0

empty string

empty array

empty object (without any iterable properties)

@function isEmpty
@memberof mi2JS(core)

@param obj
*/
$.isEmpty = function(obj){
	if(obj === void 0 || obj === null || obj === 0) return true;
	if(obj instanceof Array || typeof obj == 'string') return obj.length == 0;
	if(typeof obj == 'object'){
		for(var p in obj) return false;
		return true;
	}
	return false;
};

/** Uses {@link mi2JS(core).fixEvent}. Listen for event on an object. Any object that has either
addEventListener or attachEvent.

@function listen
@memberof mi2JS(core)
@param {Object} obj object that will generate the event
@param {String} evt event name
@param {Function} fnc callback
@param {Object} self callback function scope ( bind will be performed )
@param {boolean|object} options options parameter for addEventListener
*/
$.listen = function ( obj, evt, fnc, self, useCapture ){

//	$.nn('$.listen', {obj:obj, evt:evt, fnc:fnc} );

	var listener = function(evt){
		if(typeof(fnc) == 'string') fnc = self[fnc];
		fnc.call(self || obj, $.fixEvent(evt));
	};

	if (obj.addEventListener){
		obj.addEventListener(evt,listener,useCapture);
		return true;
	}
	else
		return obj.attachEvent("on"+evt,listener);
};

/** Used by {@link mi2JS(core).listen}. Do some cleaning on the event object provided by the browser, for easier handling of browser differences.
This is likely more extensive in other libraries. Override it if you need more.

@function fixEvent
@memberof mi2JS(core)
@param {Event} evt Browser  event
*/
$.fixEvent = function(evt){
	evt = evt || window.event;
	evt.stop = function() {
		if(this.preventDefault){
			this.preventDefault();
			this.stopPropagation();
		} else {
			this.returnValue = false;
		}
	};

	evt.target = evt.target || evt.srcElement;

	evt.pointerX = function() {
		return this.pageX || (this.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
	};

	evt.pointerY = function() {
		return this.pageY || (this.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
	};

	return evt;
};

}());
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var redis = require("redis");
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.on('connection', function (socket) {
    console.log('a user connected');
    socket.on('disconnect', function (msg) {
        console.log(socket.user.name + ' disconnected');
        socket.broadcast.to(getRoom(socket.user)).emit('messageChannel', {status:'User disconneted!', message:socket.user.name + ' left the room.'});
    });
    socket.on('joinRoom', function (msg) {
        console.log(msg.name + ' joined ' + getRoom(msg));
        socket.user = msg;
        socket.join(getRoom(msg));
        var clientsConnected = Object.keys(io.sockets.connected).length;
        if (clientsConnected > 1) {
            var clients_in_the_room = io.sockets.adapter.rooms[getRoom(msg)];
            for (var clientId in clients_in_the_room) {
                if (clientId != socket.id) {
                    var client_socket = io.sockets.connected[clientId];
                    client_socket.emit('syncClient', {clientId: socket.id})
                    break;
                }
            }
        } else if (clientsConnected == 1) {
            var redisClient = redis.createClient();
            var room = getRoom(msg);
            redisClient.get(room, function (err, canvas) {
                if(canvas != '') {
                    console.log("Getting saved canvas:  " + room);
                    io.sockets.in(room).emit('updateCanvas', {canvas: canvas});
                }
            })
        }

        socket.broadcast.to(getRoom(socket.user)).emit('messageChannel', {status:'New user!', message:socket.user.name + ' joined.'});
    });
    socket.on('syncClient', function (msg) {
        io.sockets.connected[msg.clientId].emit('updateCanvas', {canvas: msg.canvas});
    })
    socket.on('saveCanvas', function (msg) {
        var redisClient = redis.createClient();
        var room = getRoom(msg);
        redisClient.set(room, msg.canvas, redis.print);
        console.log("saving: " + room);
        var messageToSend = {};
        messageToSend.status = 'Success.';
        messageToSend.message = 'Canvas saved.'
        io.sockets.in(room).emit('messageChannel', messageToSend);
    })

    socket.on('messageChannel', function(msg){
        io.sockets.in(room).emit('messageChannel', msg);
    });

    addListener('addObject');
    addListener('removeObject');
    addListener('writing');
    addListener('scaling');
    addListener('rotating');
    addListener('moving');
    function addListener(name) {
        socket.on(name, function (msg) {
            var user = socket.user;
            if (user) {
                socket.broadcast.to(getRoom(user)).emit(name, msg);
            }
        });
    };
    function getRoom(user) {
        return user.randomString + "/" + user.room;
    }
});
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(express.static(__dirname + '/public_html'));
app.use("*", function (req, res) {
    res.sendFile(__dirname + '/public_html/index.html');
});
// TODO: error handlers
var debug = require('debug')('notewithme');
//var app = require('../app');
app.set('port', process.env.PORT || 3000);
var server = http.listen(app.get('port'), function () {
    debug('Express server listening on port ' + server.address().port);
});
module.exports = app;
<commit_msg>refactoring<commit_after>var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var redis = require("redis");
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.on('connection', function (socket) {
    console.log('a user connected');
    socket.on('disconnect', function (msg) {
        console.log(socket.user.name + ' disconnected');
        socket.broadcast.to(getRoom(socket.user)).emit('messageChannel', messageForChannel('User disconneted!', socket.user.name + ' left the room.'));
    });
    socket.on('joinRoom', function (msg) {
        console.log(msg.name + ' joined ' + getRoom(msg));
        socket.user = msg;
        socket.join(getRoom(msg));
        var clientsConnected = Object.keys(io.sockets.connected).length;

        if (clientsConnected == 1) {
            checkIfHasExistingCanvasAndUpdateCanvas();
        } else if (clientsConnected > 1) {
            findFirstClientAndAskForSync();
        }

        function checkIfHasExistingCanvasAndUpdateCanvas() {
            var redisClient = redis.createClient();
            var room = getRoom(msg);
            redisClient.get(room, function (err, canvas) {
                if (canvas != '') {
                    console.log("Getting saved canvas:  " + room);
                    sendMessageToAllIn(room).emit('updateCanvas', {canvas: canvas});
                }
            })
        }

        function findFirstClientAndAskForSync() {
            var clients_in_the_room = io.sockets.adapter.rooms[getRoom(msg)];
            for (var clientId in clients_in_the_room) {
                if (clientId != socket.id) {
                    var client_socket = io.sockets.connected[clientId];
                    client_socket.emit('syncClient', {clientId: socket.id})
                    break;
                }
            }
        }

        sendToAllInRoomButMe(getRoom(socket.user)).emit('messageChannel', messageForChannel('New user!', socket.user.name + ' joined.'));
    });

    function messageForChannel(status, message){
        return {status:status, message:message};
    }
    socket.on('syncClient', function (msg) {
        io.sockets.connected[msg.clientId].emit('updateCanvas', {canvas: msg.canvas});
    })
    function sendMessageToAllIn(room) {
        return io.sockets.in(room);
    }

    function sendToAllInRoomButMe(room) {
        return socket.broadcast.to(room);
    }
    socket.on('saveCanvas', function (msg) {
        var redisClient = redis.createClient();
        var room = getRoom(msg);
        redisClient.set(room, msg.canvas, redis.print);
        console.log("Saving: " + room);
        sendMessageToAllIn(room).emit('messageChannel', messageForChannel('Success.', 'Canvas saved.'));
    })

    socket.on('messageChannel', function(msg){
        sendMessageToAllIn(room).emit('messageChannel', msg);
    });

    addListener('addObject');
    addListener('removeObject');
    addListener('writing');
    addListener('scaling');
    addListener('rotating');
    addListener('moving');

    function addListener(name) {
        socket.on(name, function (msg) {
            var user = socket.user;
            if (user) {
                sendToAllInRoomButMe(getRoom(room)).emit(name, msg);
            }
        });
    };
    function getRoom(user) {
        return user.randomString + "/" + user.room;
    }
});
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(express.static(__dirname + '/public_html'));
app.use("*", function (req, res) {
    res.sendFile(__dirname + '/public_html/index.html');
});
// TODO: error handlers
var debug = require('debug')('notewithme');
//var app = require('../app');
app.set('port', process.env.PORT || 3000);
var server = http.listen(app.get('port'), function () {
    debug('Express server listening on port ' + server.address().port);
});
module.exports = app;
<|endoftext|>


<commit_before>/**
 * MT940 parser class
 * @module lib/parser
 */

const Tags         = require('./tags');
const helperModels = require('./helperModels');

/**
 * Main parser class, parses input text (e.g. read from a file) into array of statements.
 * Each statement is validated for: all strictly required tags,
 * opening/closing balance currency is the same, opening balance + turnover = closing balance.
 * One input may return one or more statements (as array). Each statement contains transactions
 * array, where each contains data of tag 61 (and tag 86 for details).
 *
Output statement contains:

 * @property {string} transactionReference - tag 20 reference
 * @property {string} relatedReference - tag 21 reference, optional
 * @property {string} accountIdentification - tag 25 own bank account identification
 * @property {string} number.statement - tag 28 main statement number
 * @property {string} number.sequence - tag 28 statement sub number (sequence)
 * @property {string} number.section - tag 28 statement sub sub number (present on some banks)
 * @property {Date}   openingBalanceDate - tag 60 statement opening date
 * @property {Date}   closingBalanceDate - tag 62 statement closing date
 * @property {Date} closingAvailableBalanceDate - closing available balance date (field 64)
 * @property {Date} forwardAvailableBalanceDate - forward available balance date (field 65)
 * @property {Date}   statementDate - abstraction for statement date = `closingBalanceDate`
 * @property {string} currency - statement currency
 * @property {Number} openingBalance - beginning balance of the statement
 * @property {Number} closingBalance - ending balance of the statement
 * @property {Number} closingAvailableBalance - closing available balance (field 64)
 * @property {Number} forwardAvailableBalance - forward available balance (field 65)
 *
 * @property {array}  transactions - collection of transactions
 * @property {Date}   transaction.date - transaction date
 * @property {Number} transaction.amount - transaction amount (with sign, Credit+, Debit-)
 * @property {Boolean} transaction.isReversal - reversal transaction
 * @property {string} transaction.currency - transaction currency (copy of statement currency)
 * @property {string} transaction.details - content of relevant 86 tag(s), may be multiline (`\n` separated)
 * @property {string} transaction.transactionType - MT940 transaction type code (e.g. NTRF ...)
 * @property {string} transaction.reference - payment reference field
 * @property {Date}   transaction.entryDate - optional, entry date field
 * @property {string} transaction.fundsCode - optional, funds code field
 * @property {string} transaction.bankReference - optional, bank reference
 * @property {string} transaction.extraDetails - optional, extra details
 * @example
 * const mt940parser = new Parser();
 * const statements  = parser.parse(fs.readFileSync(path, 'utf8'));
 * for (let i of statements) {
 *   console.log(i.number.statement, i.statementDate);
 *   for (let t of i.transactions) {
 *     console.log(t.amount, t.currency);
 *   }
 * }
 */
class Parser {

  /**
  * Parse text data into array of statements
  * @param {string} data - text unparsed bank statement in MT940 format
  * @param {boolean} withTags - tags will be copied to output statements in `tags` attribute for further analysis
  * @return {array} Array of statements @see class documentation for details
  */
  parse(data, withTags = false) {
    const factory    = new Tags.TagFactory();
    const dataLines  = this._splitAndNormalize(data);
    const tagLines   = [...this._parseLines(dataLines)];
    const tags       = tagLines.map(i => factory.createTag(i.id, i.subId, i.data.join('\n')));
    const tagGroups  = this._groupTags(tags);
    const statements = tagGroups.map((grp, idx) => {
      this._validateGroup(grp, idx+1);
      return this._buildStatement(grp, withTags);
    });

    return statements;
  }

  /**
  * Split text into lines, replace clutter, remove empty lines ...
  * @private
  */
  _splitAndNormalize(data) {
    return data
      .split('\n')
      .map(line => {
        return line
          .replace('\r', '')
          .replace(/\s+$/, '');
      })
      .filter(line => !!line && line !== '-');
  }

  /**
  * Convert lines into separate tags
  * @private
  */
  *_parseLines(lines) {
    const reTag = /^:([0-9]{2}|NS)([A-Z])?:/;
    let tag = {};

    for (let i of lines) {

      if (i.startsWith('-}') || i.startsWith('{')) {
        continue; // Skip message headers
      }

      let match = i.match(reTag);
      if (match) { // Tag found
        if (tag.id) { yield tag } // Yield previous
        tag = { // Start new tag
          id:    match[1],
          subId: match[2] || '',
          data:  [i.substr(match[0].length)]
        };
      } else { // Add a line to previous tag
        tag.data.push(i);
      }
    }

    if (tag.id) { yield tag } // Yield last
  }

  /**
  * Group tags into statements
  * @private
  */
  _groupTags(tags) {
    return tags.reduce((prev, i) => {
      if (i instanceof Tags.TagTransactionReferenceNumber) {
        prev.push([]); // Statement starting tag -> start new group
      }
      prev[prev.length-1].push(i);
      return prev;
    }, []);
  }

  /**
  * Validate group of tags (required tags present, currency is consistent, consistent balances vs turnover)
  * @private
  */
  _validateGroup(group, idx) {
    // Check mandatory tags
    const mandatoryTags = [
      Tags.TagTransactionReferenceNumber, //20
      Tags.TagAccountIdentification,      //25
      Tags.TagStatementNumber,            //28
      Tags.TagOpeningBalance,             //60
      Tags.TagClosingBalance              //62
    ];
    for (let Tag of mandatoryTags) {
      if (!group.find(t => t instanceof Tag)) {
        throw Error(`Mandatory tag ${Tag.ID} is missing in group ${idx}`);
      }
    }

    // Check same currency
    let currency = '';
    for (let i of group.filter(i => i instanceof Tags.TagBalance)) {
      if (!currency) {
        currency = i.fields.currency;
      } else if (currency !== i.fields.currency) {
        throw Error(`Currency markers are differ [${currency}, ${i.fields.currency}] in group ${idx}`);
      }
    }

    // Check turnover
    const ob = group.find(i => i instanceof Tags.TagOpeningBalance);
    const cb = group.find(i => i instanceof Tags.TagClosingBalance);
    const turnover = cb.fields.amount - ob.fields.amount;

    const sumLines = group
      .filter(i => i instanceof Tags.TagStatementLine)
      .reduce((prev, cur) => prev + cur.fields.amount, 0.0);

    if (!helperModels.Amount.isEqual(sumLines, turnover)) {
      throw Error(`Sum of lines (${sumLines}) != turnover (${turnover}) in group ${idx}`);
    }
  }

  /**
  * Build statement objects
  * @private
  */
  _buildStatement(group, withTags) {
    let statement = {
      transactionReference:  '',
      relatedReference:      '',
      accountIdentification: '',
      number: {
        statement: '',
        sequence:  '',
        section:   ''
      },
      statementDate:      null,
      openingBalanceDate: null,
      closingBalanceDate: null,
      currency:           '',
      openingBalance:     0.0,
      closingBalance:     0.0,
      transactions:       [],
      closingAvailableBalanceDate: null,
      forwardAvailableBalanceDate: null,
      closingAvailableBalance:     0.0,
      forwardAvailableBalance:     0.0,
    };

    for (let tag of group) {
      if (tag instanceof Tags.TagTransactionReferenceNumber) {
        statement.transactionReference = tag.fields.transactionReference;
      }
      if (tag instanceof Tags.TagRelatedReference) {
        statement.relatedReference = tag.fields.relatedReference;
      }
      if (tag instanceof Tags.TagAccountIdentification) {
        statement.accountIdentification = tag.fields.accountIdentification;
      }
      if (tag instanceof Tags.TagStatementNumber) {
        statement.number.statement = tag.fields.statementNumber;
        statement.number.sequence  = tag.fields.sequenceNumber;
        statement.number.section   = tag.fields.sectionNumber;
      }
      if (tag instanceof Tags.TagOpeningBalance) {
        statement.openingBalanceDate = tag.fields.date;
        statement.openingBalance     = tag.fields.amount;
        statement.currency           = tag.fields.currency;
      }
      if (tag instanceof Tags.TagClosingBalance) {
        statement.closingBalanceDate = tag.fields.date;
        statement.statementDate      = tag.fields.date;
        statement.closingBalance     = tag.fields.amount;
      }
      if (tag instanceof Tags.TagClosingAvailableBalance) {
        statement.closingAvailableBalanceDate = tag.fields.date;
        statement.closingAvailableBalance     = tag.fields.amount;
      }
      if (tag instanceof Tags.TagForwardAvailableBalance) {
        statement.forwardAvailableBalanceDate = tag.fields.date;
        statement.forwardAvailableBalance     = tag.fields.amount;
      }
      if (tag instanceof Tags.TagStatementLine) {
        statement.transactions.push(Object.assign({},
          tag.fields,
          {
            currency: statement.currency,
            details: ''
          }
        ));
      }
      if (tag instanceof Tags.TagTransactionDetails) {
        let t = statement.transactions[statement.transactions.length - 1];
        t.details  += (t.details && '\n') + tag.fields.transactionDetails;
      }
    }

    for (let t of statement.transactions) {
      let structuredDetails = this._detectDetailStructure(t);
      if (structuredDetails) t.structuredDetails = structuredDetails;
    }
    if (withTags) { statement.tags = group } // preserve tags
    if (!statement.closingAvailableBalanceDate) {
      statement.closingAvailableBalanceDate = new Date(statement.closingBalanceDate);
      statement.closingAvailableBalance     = statement.closingBalance;
    }
    if (!statement.forwardAvailableBalanceDate) {
      statement.forwardAvailableBalanceDate = new Date(statement.closingAvailableBalanceDate);
      statement.forwardAvailableBalance     = statement.closingAvailableBalance;
    }

    return statement;
  }

  /**
  * Detects if field 86 is structured and attempts to parse it
  * @private
  */
  _detectDetailStructure(transaction) {
    const details = transaction.details.replace(/\n/g, '');
    const prefix  = details.charAt();
    let splitRule = {};

    // check first symbol is known separator
    if (prefix === '/') {                // assume /XXX/ fields
      const tagRe    = '\\/[0-9A-Z]{2,4}\\/';
      splitRule.test = `^${tagRe}`;
      splitRule.line = `(?=${tagRe})`;
      splitRule.item = '\\/([0-9A-Z]{2,4})\\/(.*)';
    } else if ('>?'.includes(prefix)) {  // assume >DD fields
      splitRule.test = '^\\' + prefix + '\\d{2}';
      splitRule.line = '\\'  + prefix + '(?=\\d{2})';
      splitRule.item = '(\\d{2})(.*)';
    } else return; // known separator not found

    if (!(new RegExp(splitRule.test)).test(details)) return; // string must start with tag

    const matches = details.split(new RegExp(splitRule.line));
    if (matches.length > 0 && matches[0].length === 0) matches.shift(); // remove empty match at start
    console.log(matches);
    if (matches.length === 0) return; // no matches found - TODO: refactor ???

    const itemRe = new RegExp(splitRule.item);
    const parsedStruc = matches
      .map(m => m.match(itemRe)) // supposed to match groups 1 and 2
      .reduce((struc, m) => Object.assign(struc, { [m[1]]: m[2] }), {});
    return parsedStruc;
  }
}

module.exports = Parser;
<commit_msg>_detectDetailStructure improvements<commit_after>/**
 * MT940 parser class
 * @module lib/parser
 */

const Tags         = require('./tags');
const helperModels = require('./helperModels');

/**
 * Main parser class, parses input text (e.g. read from a file) into array of statements.
 * Each statement is validated for: all strictly required tags,
 * opening/closing balance currency is the same, opening balance + turnover = closing balance.
 * One input may return one or more statements (as array). Each statement contains transactions
 * array, where each contains data of tag 61 (and tag 86 for details).
 *
Output statement contains:

 * @property {string} transactionReference - tag 20 reference
 * @property {string} relatedReference - tag 21 reference, optional
 * @property {string} accountIdentification - tag 25 own bank account identification
 * @property {string} number.statement - tag 28 main statement number
 * @property {string} number.sequence - tag 28 statement sub number (sequence)
 * @property {string} number.section - tag 28 statement sub sub number (present on some banks)
 * @property {Date}   openingBalanceDate - tag 60 statement opening date
 * @property {Date}   closingBalanceDate - tag 62 statement closing date
 * @property {Date} closingAvailableBalanceDate - closing available balance date (field 64)
 * @property {Date} forwardAvailableBalanceDate - forward available balance date (field 65)
 * @property {Date}   statementDate - abstraction for statement date = `closingBalanceDate`
 * @property {string} currency - statement currency
 * @property {Number} openingBalance - beginning balance of the statement
 * @property {Number} closingBalance - ending balance of the statement
 * @property {Number} closingAvailableBalance - closing available balance (field 64)
 * @property {Number} forwardAvailableBalance - forward available balance (field 65)
 *
 * @property {array}  transactions - collection of transactions
 * @property {Date}   transaction.date - transaction date
 * @property {Number} transaction.amount - transaction amount (with sign, Credit+, Debit-)
 * @property {Boolean} transaction.isReversal - reversal transaction
 * @property {string} transaction.currency - transaction currency (copy of statement currency)
 * @property {string} transaction.details - content of relevant 86 tag(s), may be multiline (`\n` separated)
 * @property {string} transaction.transactionType - MT940 transaction type code (e.g. NTRF ...)
 * @property {string} transaction.reference - payment reference field
 * @property {Date}   transaction.entryDate - optional, entry date field
 * @property {string} transaction.fundsCode - optional, funds code field
 * @property {string} transaction.bankReference - optional, bank reference
 * @property {string} transaction.extraDetails - optional, extra details
 * @example
 * const mt940parser = new Parser();
 * const statements  = parser.parse(fs.readFileSync(path, 'utf8'));
 * for (let i of statements) {
 *   console.log(i.number.statement, i.statementDate);
 *   for (let t of i.transactions) {
 *     console.log(t.amount, t.currency);
 *   }
 * }
 */
class Parser {

  /**
  * Parse text data into array of statements
  * @param {string} data - text unparsed bank statement in MT940 format
  * @param {boolean} withTags - tags will be copied to output statements in `tags` attribute for further analysis
  * @return {array} Array of statements @see class documentation for details
  */
  parse(data, withTags = false) {
    const factory    = new Tags.TagFactory();
    const dataLines  = this._splitAndNormalize(data);
    const tagLines   = [...this._parseLines(dataLines)];
    const tags       = tagLines.map(i => factory.createTag(i.id, i.subId, i.data.join('\n')));
    const tagGroups  = this._groupTags(tags);
    const statements = tagGroups.map((grp, idx) => {
      this._validateGroup(grp, idx+1);
      return this._buildStatement(grp, withTags);
    });

    return statements;
  }

  /**
  * Split text into lines, replace clutter, remove empty lines ...
  * @private
  */
  _splitAndNormalize(data) {
    return data
      .split('\n')
      .map(line => {
        return line
          .replace('\r', '')
          .replace(/\s+$/, '');
      })
      .filter(line => !!line && line !== '-');
  }

  /**
  * Convert lines into separate tags
  * @private
  */
  *_parseLines(lines) {
    const reTag = /^:([0-9]{2}|NS)([A-Z])?:/;
    let tag = {};

    for (let i of lines) {

      if (i.startsWith('-}') || i.startsWith('{')) {
        continue; // Skip message headers
      }

      let match = i.match(reTag);
      if (match) { // Tag found
        if (tag.id) { yield tag } // Yield previous
        tag = { // Start new tag
          id:    match[1],
          subId: match[2] || '',
          data:  [i.substr(match[0].length)]
        };
      } else { // Add a line to previous tag
        tag.data.push(i);
      }
    }

    if (tag.id) { yield tag } // Yield last
  }

  /**
  * Group tags into statements
  * @private
  */
  _groupTags(tags) {
    return tags.reduce((prev, i) => {
      if (i instanceof Tags.TagTransactionReferenceNumber) {
        prev.push([]); // Statement starting tag -> start new group
      }
      prev[prev.length-1].push(i);
      return prev;
    }, []);
  }

  /**
  * Validate group of tags (required tags present, currency is consistent, consistent balances vs turnover)
  * @private
  */
  _validateGroup(group, idx) {
    // Check mandatory tags
    const mandatoryTags = [
      Tags.TagTransactionReferenceNumber, //20
      Tags.TagAccountIdentification,      //25
      Tags.TagStatementNumber,            //28
      Tags.TagOpeningBalance,             //60
      Tags.TagClosingBalance              //62
    ];
    for (let Tag of mandatoryTags) {
      if (!group.find(t => t instanceof Tag)) {
        throw Error(`Mandatory tag ${Tag.ID} is missing in group ${idx}`);
      }
    }

    // Check same currency
    let currency = '';
    for (let i of group.filter(i => i instanceof Tags.TagBalance)) {
      if (!currency) {
        currency = i.fields.currency;
      } else if (currency !== i.fields.currency) {
        throw Error(`Currency markers are differ [${currency}, ${i.fields.currency}] in group ${idx}`);
      }
    }

    // Check turnover
    const ob = group.find(i => i instanceof Tags.TagOpeningBalance);
    const cb = group.find(i => i instanceof Tags.TagClosingBalance);
    const turnover = cb.fields.amount - ob.fields.amount;

    const sumLines = group
      .filter(i => i instanceof Tags.TagStatementLine)
      .reduce((prev, cur) => prev + cur.fields.amount, 0.0);

    if (!helperModels.Amount.isEqual(sumLines, turnover)) {
      throw Error(`Sum of lines (${sumLines}) != turnover (${turnover}) in group ${idx}`);
    }
  }

  /**
  * Build statement objects
  * @private
  */
  _buildStatement(group, withTags) {
    let statement = {
      transactionReference:  '',
      relatedReference:      '',
      accountIdentification: '',
      number: {
        statement: '',
        sequence:  '',
        section:   ''
      },
      statementDate:      null,
      openingBalanceDate: null,
      closingBalanceDate: null,
      currency:           '',
      openingBalance:     0.0,
      closingBalance:     0.0,
      transactions:       [],
      closingAvailableBalanceDate: null,
      forwardAvailableBalanceDate: null,
      closingAvailableBalance:     0.0,
      forwardAvailableBalance:     0.0,
    };

    for (let tag of group) {
      if (tag instanceof Tags.TagTransactionReferenceNumber) {
        statement.transactionReference = tag.fields.transactionReference;
      }
      if (tag instanceof Tags.TagRelatedReference) {
        statement.relatedReference = tag.fields.relatedReference;
      }
      if (tag instanceof Tags.TagAccountIdentification) {
        statement.accountIdentification = tag.fields.accountIdentification;
      }
      if (tag instanceof Tags.TagStatementNumber) {
        statement.number.statement = tag.fields.statementNumber;
        statement.number.sequence  = tag.fields.sequenceNumber;
        statement.number.section   = tag.fields.sectionNumber;
      }
      if (tag instanceof Tags.TagOpeningBalance) {
        statement.openingBalanceDate = tag.fields.date;
        statement.openingBalance     = tag.fields.amount;
        statement.currency           = tag.fields.currency;
      }
      if (tag instanceof Tags.TagClosingBalance) {
        statement.closingBalanceDate = tag.fields.date;
        statement.statementDate      = tag.fields.date;
        statement.closingBalance     = tag.fields.amount;
      }
      if (tag instanceof Tags.TagClosingAvailableBalance) {
        statement.closingAvailableBalanceDate = tag.fields.date;
        statement.closingAvailableBalance     = tag.fields.amount;
      }
      if (tag instanceof Tags.TagForwardAvailableBalance) {
        statement.forwardAvailableBalanceDate = tag.fields.date;
        statement.forwardAvailableBalance     = tag.fields.amount;
      }
      if (tag instanceof Tags.TagStatementLine) {
        statement.transactions.push(Object.assign({},
          tag.fields,
          {
            currency: statement.currency,
            details: ''
          }
        ));
      }
      if (tag instanceof Tags.TagTransactionDetails) {
        let t = statement.transactions[statement.transactions.length - 1];
        t.details  += (t.details && '\n') + tag.fields.transactionDetails;
      }
    }

    for (let t of statement.transactions) {
      let structuredDetails = this._detectDetailStructure(t);
      if (structuredDetails) t.structuredDetails = structuredDetails;
    }
    if (withTags) { statement.tags = group } // preserve tags
    if (!statement.closingAvailableBalanceDate) {
      statement.closingAvailableBalanceDate = new Date(statement.closingBalanceDate);
      statement.closingAvailableBalance     = statement.closingBalance;
    }
    if (!statement.forwardAvailableBalanceDate) {
      statement.forwardAvailableBalanceDate = new Date(statement.closingAvailableBalanceDate);
      statement.forwardAvailableBalance     = statement.closingAvailableBalance;
    }

    return statement;
  }

  /**
  * Detects if field 86 is structured and attempts to parse it
  * @private
  */
  _detectDetailStructure(transaction) {
    const details = transaction.details.replace(/\n/g, '');
    const prefix  = details.charAt();

    // check first symbol is known separator
    let tagRe;
    if (prefix === '/') {                // assume /XXX/ fields
      tagRe = '\\/[0-9A-Z]{2,4}\\/';
    } else if ('>?'.includes(prefix)) {  // assume >DD fields
      tagRe = `\\${prefix}\\d{2}`;
    } else return; // known separator not found

    const rule = {
      detect: new RegExp(`^${tagRe}`),
      split:  new RegExp(`(?=${tagRe})`),
      item:   new RegExp(`^(${tagRe})(.*)`),
    };
    const stripPrefixRe = new RegExp(`\\${prefix}`, 'g');

    if (!rule.detect.test(details)) return; // string must start with tag

    const matches = details.split(rule.split);
    if (matches.length > 0 && matches[0].length === 0) matches.shift(); // remove empty match at start
    if (matches.length === 0) return; // no matches found
    console.log(matches);

    const parsedStruc = matches
      .map(m => m.match(rule.item)) // supposed to match groups 1 and 2
      .map(m => [ m[1].replace(stripPrefixRe, ''), m[2] ]) // remove prefix symbols from tag
      .reduce((struc, m) => Object.assign(struc, { [m[0]]: m[1] }), {});

    return parsedStruc;
  }
}

module.exports = Parser;
<|endoftext|>


<commit_before>/*
 * jQuery Behavior Plugin: Define rich behaviors that include both event
 * handlers and (un)transformations on DOM elements.
 *
 * Copyright (c) 2011 Florian Schäfer (florian.schaefer@gmail.com)
 * Dual licensed under the MIT (MIT_LICENSE.txt)
 * and GPL Version 2 (GPL_LICENSE.txt) licenses.
 *
 * Version: 1.4
 * Requires: jQuery 1.7+ plus modified Live Query 1.1.1
 *
 */
(function ($, attr) {

    // jQuery supports getData, setData and changeData,
    // support getAttr, setAttr, changeAttr too.
    $.attr = function (elem, name, value) {
        var current = attr(elem, name),
            // read current value.
            retval = current;

        if (!value) {
            // we are getting a value.
            $.event.trigger('getAttr', {
                attribute: name,
                from: current,
                to: value
            }, elem);
        } else { // writing
            // we are setting a value.
            $.event.trigger('setAttr', {
                attribute: name,
                from: current,
                to: value
            }, elem);

            retval = attr.apply(this, arguments); // call original.
            // value or type changed.
            if (current !== value) {
                $.event.trigger('changeAttr', {
                    attribute: name,
                    from: current,
                    to: value
                }, elem);
            }
        }
        return retval; // return original
    };

})(jQuery, jQuery.attr);

(function ($, undefined) {

    if (!$.livequery) {
        throw "jquery.behavior.js: jQuery Plugin: Live Query not loaded.";
    }

    $.behavior = function (metabehaviors, context) {

        context = context || window.document;

        // Handle $.behavior(function () {}).
        if ($.isFunction(metabehaviors)) {
            metabehaviors = metabehaviors();
        }

        // Handle $.behavior(""), $.behavior(null), or $.behavior(undefined).
        if (!metabehaviors) {
            return this;
        }

        // Handle $.behavior([{ ... }, { ... }, ... ], [context]).
        if ($.isArray(metabehaviors)) {
            return $.each(metabehaviors, function () {
                $.behavior(this, context);
            });
        }

        // Handle $.behavior({ ... }, [context]).
        return $.each(metabehaviors, function (selector, metabehavior) {

            // Cache element.
            var $elementInContext = $(selector, context);

            // Evaluate metabehavior if it's a function.
            if ($.isFunction(metabehavior)) {
                metabehavior = metabehavior.call($elementInContext);
            }

            // Provide at least noop functions for transform and untransform.
            metabehavior = $.extend({
                transform: $.noop,
                untransform: $.noop
            }, metabehavior);

            // Bind all events.
            for (var event in metabehavior) {

                if (metabehavior.hasOwnProperty(event)) {

                    switch (event) {
                    case 'transform':
                    case 'untransform':
                        // Don't handle these here.
                        continue;

                    default:
                        $elementInContext.livequery(event, metabehavior[event]);
                        break;
                    }

                }

            }

            // Transform DOM element.
            $elementInContext.livequery(metabehavior.transform, metabehavior.untransform);

        });
    };

    $.fn.behavior = function (metabehaviors) {
        return this.each(function () {
            $.behavior(metabehaviors, this);
        });
    };

    $(function () {
        $('script[type="text/behavior"]').livequery(function () {
            $.behavior(eval('({' + $(this).text() + '})'));
        });
    });

})(jQuery);
<commit_msg>Remove trailing whitespaces.<commit_after>/*
 * jQuery Behavior Plugin: Define rich behaviors that include both event
 * handlers and (un)transformations on DOM elements.
 *
 * Copyright (c) 2011 Florian Schäfer (florian.schaefer@gmail.com)
 * Dual licensed under the MIT (MIT_LICENSE.txt)
 * and GPL Version 2 (GPL_LICENSE.txt) licenses.
 *
 * Version: 1.4
 * Requires: jQuery 1.7+ plus modified Live Query 1.1.1
 *
 */
(function ($, attr) {

    // jQuery supports getData, setData and changeData,
    // support getAttr, setAttr, changeAttr too.
    $.attr = function (elem, name, value) {
        var current = attr(elem, name),
            // read current value.
            retval = current;

        if (!value) {
            // we are getting a value.
            $.event.trigger('getAttr', {
                attribute: name,
                from: current,
                to: value
            }, elem);
        } else { // writing
            // we are setting a value.
            $.event.trigger('setAttr', {
                attribute: name,
                from: current,
                to: value
            }, elem);

            retval = attr.apply(this, arguments); // call original.
            // value or type changed.
            if (current !== value) {
                $.event.trigger('changeAttr', {
                    attribute: name,
                    from: current,
                    to: value
                }, elem);
            }
        }
        return retval; // return original
    };

})(jQuery, jQuery.attr);

(function ($, undefined) {

    if (!$.livequery) {
        throw "jquery.behavior.js: jQuery Plugin: Live Query not loaded.";
    }

    $.behavior = function (metabehaviors, context) {

        context = context || window.document;

        // Handle $.behavior(function () {}).
        if ($.isFunction(metabehaviors)) {
            metabehaviors = metabehaviors();
        }

        // Handle $.behavior(""), $.behavior(null), or $.behavior(undefined).
        if (!metabehaviors) {
            return this;
        }

        // Handle $.behavior([{ ... }, { ... }, ... ], [context]).
        if ($.isArray(metabehaviors)) {
            return $.each(metabehaviors, function () {
                $.behavior(this, context);
            });
        }

        // Handle $.behavior({ ... }, [context]).
        return $.each(metabehaviors, function (selector, metabehavior) {

            // Cache element.
            var $elementInContext = $(selector, context);

            // Evaluate metabehavior if it's a function.
            if ($.isFunction(metabehavior)) {
                metabehavior = metabehavior.call($elementInContext);
            }

            // Provide at least noop functions for transform and untransform.
            metabehavior = $.extend({
                transform: $.noop,
                untransform: $.noop
            }, metabehavior);

            // Bind all events.
            for (var event in metabehavior) {

                if (metabehavior.hasOwnProperty(event)) {

                    switch (event) {
                    case 'transform':
                    case 'untransform':
                        // Don't handle these here.
                        continue;

                    default:
                        $elementInContext.livequery(event, metabehavior[event]);
                        break;
                    }

                }

            }

            // Transform DOM element.
            $elementInContext.livequery(metabehavior.transform, metabehavior.untransform);

        });
    };

    $.fn.behavior = function (metabehaviors) {
        return this.each(function () {
            $.behavior(metabehaviors, this);
        });
    };

    $(function () {
        $('script[type="text/behavior"]').livequery(function () {
            $.behavior(eval('({' + $(this).text() + '})'));
        });
    });

})(jQuery);
<|endoftext|>


<commit_before>import React, { Component } from "react";
import { findDOMNode } from "react-dom";
import { connect } from "react-redux";
import RootReducer from "./../../redux/RootReducer";
import PropTypes from "prop-types";
import * as maptalks from "maptalks";
//import UI
import { withStyles } from "material-ui/styles";
import Paper from "material-ui/Paper";
import Button from "material-ui/Button";
// import TextField from 'material-ui/TextField';
// import Toolbar from 'material-ui/Toolbar';
/* eslint-disable flowtype/require-valid-file-annotation */

import green from "material-ui/colors/green";
import { CircularProgress } from "material-ui/Progress";
import CheckIcon from "material-ui-icons/Check";
import SaveIcon from "material-ui-icons/Save"; //保存
import Typography from "material-ui/Typography";
// import Divider from "material-ui/Divider";
import Dialog, {DialogContent} from "material-ui/Dialog";

import appConfig from "../../redux/Config";
import html2canvas from "html2canvas";
import projectData from "./../../redux/RootData";

const styles = theme => ({
  root: {
    width: "100%",
    height: `${window.innerHeight - 48}px`,
    background: "white",
    display: "flex",
    justifyContent: "center"
  },
  thematicMap: {
    position: "absolute",
    top: "7.8125%",
    width: `${window.innerHeight * 0.61875}px`,
    height: `${window.innerHeight * 0.875}px`
  },
  title: {
    padding: "2% 0 0 0",
    fontSize: "1.5em",
    fontFamily: "宋体",
    fontWeight: "800",
    height: "5%"
  },
  table:{
    position:'absolute',
    left:'7.5%',
    width:`${window.innerHeight * 0.61875*0.85}px`,
    height: `${window.innerHeight * 0.875*0.85}px`,
    borderCollapse:'collapse',
    border:'solid 2px #000'
  },
  head:{
    height: "5%",
  },
  headcell:{
    padding:0,
    border:'solid 1px #000'
  },
  headtext:{
    background:'#fff',
    width:'95%',
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
    textAlign:'center',
    padding:0,
    border:0,
  },
  mapPic:{
    padding:0,
    border:'solid 1px #000'
  },
  pic:{
    color: "#000",
    width: "100%",
    height: "100%"
  },

  bottomtable:{
    position:'absolute',
    top: "91%",
    left:'40%',
    width: `${window.innerHeight * 0.35}px`,
    padding:0,
    border:0,
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
  },
  btmtr:{
    height: `${window.innerHeight * 0.03}px`,
    width:'100%',
    padding:0,
    border:0,
  },
  btmtd:{
    padding:0,
    border:0,
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
  },
  btminput:{
    padding:0,
    border:0,
    width:'100%',
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
  },
  right: {
    position: "absolute",
    top: "62%",
    left:"92.5%",
    fontSize: "1em",
    fontFamily: "宋体",
    letterSpacing: "20px",
    width: "2%",
    height: "40%",
    padding: "0 1% 0 1%"
  },
  alert: {
    display: "flex",
    height:`${window.innerHeight * 0.12}px`,
    padding:'0 10px 0 10px',
  },
  message: {
    fontSize: "1.5em",
    color:"#455A64",
    textAlign: "center",
    lineHeight: "150%",
  },
  wrapper: {
    // position: "relative",
    position: "absolute",
    top: "90%",
    left: "75%",
    height: "6%",
    width: "6%"
  },
  successSaveButtonClass: {
    backgroundColor: green[500],
    "&:hover": {
      backgroundColor: green[700]
    }
  },
  button: {
    position: "absolute",
    top: "90%",
    left: "75%",
    height: "6%",
    width: "6%",
    padding: 0,
    border: 0,
    background: "#455A64",
    borderRadius: "8%",
    boxShadow: "1px 1px 1px 1px rgba(0, 0, 0, 0.2)"
  },
  icon: {
    height: "35%",
    width: "35%",
    color: "#fff"
  },
  bt_text: {
    fontSize: "1em",
    color: "#fff"
  },
  progress: {
    color: green[500],
    position: "absolute",
    top: -2,
    left: -2
  }
});

/**
 * @type {maptalks.Map}
 * 全局的专题图地图对象和方法
 */
let thematicMap,thematicMapDOM;

/**
 * 专题图组件
 * @class
 */
class ThematicMap extends Component {
  componentDidMount() {

    const {
      saveIsChecked,
      mapCenter,
      jzdJSONData,
      szJSONData,
      jzxJSONData,
      zdJSONData,
      zjJSONData
    } = this.props;
    if (saveIsChecked) {
      const ThematicMapDiv = this.refs.ThematicMap;
      thematicMap = new maptalks.Map(ThematicMapDiv, {
        center: mapCenter,
        zoom: 16,
        baseLayer: new maptalks.TileLayer("base", {
          crossOrigin: "anonymous",
          // 'http://webst{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
          urlTemplate:
            "http://webrd{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
          subdomains: ["01", "02", "03", "04"],
          attribution: '© Gaode.com'
        })
      });
      maptalks.Layer.fromJSON(jzdJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(szJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(jzxJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(zdJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(zjJSONData).addTo(thematicMap);
    }
  }

  render() {
    const classes = this.props.classes;
    const d= new Date();
    const date=d.getFullYear()+"年"+(d.getMonth()+1)+"月"+d.getDate()+"日";
    const {
      TuDiQuanLiRen,
      ZuoLuo,
      alertSave,
      // saveIsChecked,
      onSaveAlertClose,
      onSaveThematicMapClick,
      thematicMapSaveSuccess,
      thematicMapSaveLoading,
    } = this.props;

    let saveButtonClass = "";
    if (thematicMapSaveSuccess) {
      saveButtonClass = classes.successSaveButtonClass;
    }

    return (

        <Paper
          ref={div => {
            thematicMapDOM = div
          }}
          className={classes.thematicMap}
        >
          <Dialog
            open={alertSave}
            onRequestClose={onSaveAlertClose}
            style={{ zIndex: "999999"}}>
              <DialogContent className={classes.alert} onClick={onSaveAlertClose}>
                <Typography className={classes.message}>
                  无法获取草图绘制成果图！
请返回草图编辑界面绘制并点击保存！
                </Typography>
              </DialogContent>
          </Dialog>

          <Typography type="headline" className={classes.title}>
            不动产单元草图
          </Typography>

                  <Typography className={classes.headtext} >土地权利人</Typography>

                  <input
                  className={classes.headtext}
                  defaultValue={TuDiQuanLiRen}
                  required/>

                  <Typography className={classes.headtext} >坐落</Typography>

                  <input
                  className={classes.headtext}
                  defaultValue={ZuoLuo}
                  required/>

                调查者：

                <input className={classes.btminput} required id="investigator"/>

                调查日期：

                <input className={classes.btminput} required defaultValue={date} id="invest_time"/>

                审核者：

                <input className={classes.btminput} required id="auditor"/>

                审核日期：

                <input className={classes.btminput} required defaultValue={date} id="audit_time"/>

南宁市不动产权籍调查机构绘制

        </Paper>

          <Button
            fab
            color="primary"
            className={saveButtonClass}
            onClick={onSaveThematicMapClick}
          >
            {thematicMapSaveSuccess ? (
              <CheckIcon className={classes.icon} />
            ) : (
              <SaveIcon className={classes.icon} />
            )}

          </Button>
          {thematicMapSaveLoading && (
            <CircularProgress size={60} className={classes.progress} />
          )}

    );
  }
}

ThematicMap.PropTypes = {
  classes: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired
};

const mapStateToProps = state => {
  const sketchState = state.sketchReduce;
  const canvasSeduce = state.CanvasReduce;
  console.log(projectData.ProjectItem.F1.PrincipalName)

  return {
    TuDiQuanLiRen: projectData.ProjectItem.F1.PrincipalName,
    ZuoLuo: projectData.ProjectItem.F1.Location,
    alertSave: sketchState.alertSave,
    saveIsChecked: sketchState.saveIsChecked,
    thematicMapSaveSuccess: canvasSeduce.thematicMapSaveSuccess,
    thematicMapSaveLoading: canvasSeduce.thematicMapSaveLoading,
    mapCenter: sketchState.mapCenter,
    jzdJSONData: sketchState.jzdJSONData,
    szJSONData: sketchState.szJSONData,
    jzxJSONData:sketchState.jzxJSONData,
    zdJSONData: sketchState.zdJSONData,
    zjJSONData: sketchState.zjJSONData
  };
};

const mapDispatchToProps = dispatch => {
  return {
    onSaveAlertClose: () => {
      dispatch({
        type: "saveAlertClose"
      });
    },

    onSaveThematicMapClick: () => {
      dispatch({
        type: "SAVE_THEMATICMAP_CLICK"
      });

      console.log(findDOMNode(thematicMapDOM))
      html2canvas(findDOMNode(thematicMapDOM)).then(function(canvas) {
        console.log(canvas.toDataURL())
        const ThematicMapDataURL = canvas.toDataURL();
        const ThematicMapDataLoad = ThematicMapDataURL.slice(
          ThematicMapDataURL.indexOf(",") + 1
        );
        fetch(appConfig.fileServiceRootPath + "/project/savepicture", {
          method: "POST",
          body: ThematicMapDataLoad
        })
          .then(response => response.json())
          .then(json => {
            dispatch({
              type: "SUCCESS_SAVE_THEMATICMAP_CLICK"
            });
            setTimeout(() => {
              dispatch({
                type: "RESTARE_SUCCESS_SAVE_THEMATICMAP_CLICK"
              });
            }, 1000);
            console.log(json);
          })
          .catch(err => {
            console.log(err);
          });
      })

      // const ThematicMapDataURL = thematicMap.toDataURL();
      // const ThematicMapDataLoad = ThematicMapDataURL.slice(
      //   ThematicMapDataURL.indexOf(",") + 1
      // );
      // console.log(ThematicMapDataLoad);

      // fetch(appConfig.fileServiceRootPath + "/project/savepicture", {
      //   method: "POST",
      //   body: ThematicMapDataLoad
      // })
      //   .then(response => response.json())
      //   .then(json => {
      //     dispatch({
      //       type: "SUCCESS_SAVE_THEMATICMAP_CLICK"
      //     });
      //     setTimeout(() => {
      //       dispatch({
      //         type: "RESTARE_SUCCESS_SAVE_THEMATICMAP_CLICK"
      //       });
      //     }, 1000);
      //     console.log(json);
      //   })
      //   .catch(err => {
      //     console.log(err);
      //   });
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(
  withStyles(styles, { name: "ThematicMap" })(ThematicMap)
);

//reducer
const CanvasReduce = (
  state = {
    thematicMapImg: ImageData,
    thematicMapSaveSuccess: false,
    thematicMapSaveLoading: false
  },
  action
) => {
  let newState = JSON.parse(JSON.stringify(state));

  switch (action.type) {
    case "SAVE_THEMATICMAP_CLICK":
      if (!state.thematicMapSaveLoading) {
        newState.thematicMapSaveLoading = true;
      }
      return { ...state, ...newState };
    case "SUCCESS_SAVE_THEMATICMAP_CLICK":
      newState.thematicMapSaveLoading = false;
      newState.thematicMapSaveSuccess = true;
      return { ...state, ...newState };
    case "RESTARE_SUCCESS_SAVE_THEMATICMAP_CLICK":
      newState.thematicMapSaveSuccess = false;
      return { ...state, ...newState };
    default:
      return { ...state };
  }
};
RootReducer.merge(CanvasReduce);
<commit_msg>update thematicmap tablecell css<commit_after>import React, { Component } from "react";
import { findDOMNode } from "react-dom";
import { connect } from "react-redux";
import RootReducer from "./../../redux/RootReducer";
import PropTypes from "prop-types";
import * as maptalks from "maptalks";
//import UI
import { withStyles } from "material-ui/styles";
import Paper from "material-ui/Paper";
import Button from "material-ui/Button";
// import TextField from 'material-ui/TextField';
// import Toolbar from 'material-ui/Toolbar';
/* eslint-disable flowtype/require-valid-file-annotation */

import green from "material-ui/colors/green";
import { CircularProgress } from "material-ui/Progress";
import CheckIcon from "material-ui-icons/Check";
import SaveIcon from "material-ui-icons/Save"; //保存
import Typography from "material-ui/Typography";
// import Divider from "material-ui/Divider";
import Dialog, {DialogContent} from "material-ui/Dialog";

import appConfig from "../../redux/Config";
import html2canvas from "html2canvas";
import projectData from "./../../redux/RootData";

const styles = theme => ({
  root: {
    width: "100%",
    height: `${window.innerHeight - 48}px`,
    background: "white",
    display: "flex",
    justifyContent: "center"
  },
  thematicMap: {
    position: "absolute",
    top: "7.8125%",
    width: `${window.innerHeight * 0.61875}px`,
    height: `${window.innerHeight * 0.875}px`
  },
  title: {
    padding: "2% 0 0 0",
    fontSize: "1.5em",
    fontFamily: "宋体",
    fontWeight: "800",
    height: "5%"
  },
  table:{
    position:'absolute',
    left:'7.5%',
    width:`${window.innerHeight * 0.61875*0.85}px`,
    height: `${window.innerHeight * 0.875*0.85}px`,
    borderCollapse:'collapse',
    border:'solid 2px #000'
  },
  head:{
    height: "5%",
  },
  headcell:{
    padding:0,
    border:'solid 1px #000',
  },
  headtext:{
    background:'#fff',
    width:'95%',
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
    textAlign:'center',
    padding:0,
    border:0,
  },
  mapPic:{
    padding:0,
    border:'solid 1px #000'
  },
  pic:{
    color: "#000",
    width: "100%",
    height: "100%"
  },

  bottomtable:{
    position:'absolute',
    top: "91%",
    left:'40%',
    width: `${window.innerHeight * 0.35}px`,
    padding:0,
    border:0,
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
  },
  btmtr:{
    height: `${window.innerHeight * 0.03}px`,
    width:'100%',
    padding:0,
    border:0,
  },
  btmtd:{
    padding:0,
    border:0,
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
  },
  btminput:{
    padding:0,
    border:0,
    width:'100%',
    fontSize: "1em",
    fontFamily: "宋体",
    fontWeight: "400",
  },
  right: {
    position: "absolute",
    top: "62%",
    left:"92.5%",
    fontSize: "1em",
    fontFamily: "宋体",
    letterSpacing: "20px",
    width: "2%",
    height: "40%",
    padding: "0 1% 0 1%"
  },
  alert: {
    display: "flex",
    height:`${window.innerHeight * 0.12}px`,
    padding:'0 10px 0 10px',
  },
  message: {
    fontSize: "1.5em",
    color:"#455A64",
    textAlign: "center",
    lineHeight: "150%",
  },
  wrapper: {
    // position: "relative",
    position: "absolute",
    top: "90%",
    left: "75%",
    height: "6%",
    width: "6%"
  },
  successSaveButtonClass: {
    backgroundColor: green[500],
    "&:hover": {
      backgroundColor: green[700]
    }
  },
  button: {
    position: "absolute",
    top: "90%",
    left: "75%",
    height: "6%",
    width: "6%",
    padding: 0,
    border: 0,
    background: "#455A64",
    borderRadius: "8%",
    boxShadow: "1px 1px 1px 1px rgba(0, 0, 0, 0.2)"
  },
  icon: {
    height: "35%",
    width: "35%",
    color: "#fff"
  },
  bt_text: {
    fontSize: "1em",
    color: "#fff"
  },
  progress: {
    color: green[500],
    position: "absolute",
    top: -2,
    left: -2
  }
});

/**
 * @type {maptalks.Map}
 * 全局的专题图地图对象和方法
 */
let thematicMap,thematicMapDOM;

/**
 * 专题图组件
 * @class
 */
class ThematicMap extends Component {
  componentDidMount() {

    const {
      saveIsChecked,
      mapCenter,
      jzdJSONData,
      szJSONData,
      jzxJSONData,
      zdJSONData,
      zjJSONData
    } = this.props;
    if (saveIsChecked) {
      const ThematicMapDiv = this.refs.ThematicMap;
      thematicMap = new maptalks.Map(ThematicMapDiv, {
        center: mapCenter,
        zoom: 16,
        baseLayer: new maptalks.TileLayer("base", {
          crossOrigin: "anonymous",
          // 'http://webst{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
          urlTemplate:
            "http://webrd{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
          subdomains: ["01", "02", "03", "04"],
          attribution: '© Gaode.com'
        })
      });
      maptalks.Layer.fromJSON(jzdJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(szJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(jzxJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(zdJSONData).addTo(thematicMap);
      maptalks.Layer.fromJSON(zjJSONData).addTo(thematicMap);
    }
  }

  render() {
    const classes = this.props.classes;
    const d= new Date();
    const date=d.getFullYear()+"年"+(d.getMonth()+1)+"月"+d.getDate()+"日";
    const {
      TuDiQuanLiRen,
      ZuoLuo,
      alertSave,
      // saveIsChecked,
      onSaveAlertClose,
      onSaveThematicMapClick,
      thematicMapSaveSuccess,
      thematicMapSaveLoading,
    } = this.props;

    let saveButtonClass = "";
    if (thematicMapSaveSuccess) {
      saveButtonClass = classes.successSaveButtonClass;
    }

    return (

        <Paper
          ref={div => {
            thematicMapDOM = div
          }}
          className={classes.thematicMap}
        >
          <Dialog
            open={alertSave}
            onRequestClose={onSaveAlertClose}
            style={{ zIndex: "999999"}}>
              <DialogContent className={classes.alert} onClick={onSaveAlertClose}>
                <Typography className={classes.message}>
                  无法获取草图绘制成果图！
请返回草图编辑界面绘制并点击保存！
                </Typography>
              </DialogContent>
          </Dialog>

          <Typography type="headline" className={classes.title}>
            不动产单元草图
          </Typography>

                  <Typography className={classes.headtext} >土地权利人</Typography>

                  <textarea
                  className={classes.headtext}
                  defaultValue={TuDiQuanLiRen}
                  style={{height:'50%'}}
                  required/>

                  <Typography className={classes.headtext} >坐落</Typography>

                  <textarea
                  className={classes.headtext}
                  defaultValue={ZuoLuo}
                  required/>

                调查者：

                <input className={classes.btminput} required id="investigator"/>

                调查日期：

                <input className={classes.btminput} required defaultValue={date} id="invest_time"/>

                审核者：

                <input className={classes.btminput} required id="auditor"/>

                审核日期：

                <input className={classes.btminput} required defaultValue={date} id="audit_time"/>

南宁市不动产权籍调查机构绘制

        </Paper>

          <Button
            fab
            color="primary"
            className={saveButtonClass}
            onClick={onSaveThematicMapClick}
          >
            {thematicMapSaveSuccess ? (
              <CheckIcon className={classes.icon} />
            ) : (
              <SaveIcon className={classes.icon} />
            )}

          </Button>
          {thematicMapSaveLoading && (
            <CircularProgress size={60} className={classes.progress} />
          )}

    );
  }
}

ThematicMap.PropTypes = {
  classes: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired
};

const mapStateToProps = state => {
  const sketchState = state.sketchReduce;
  const canvasSeduce = state.CanvasReduce;
  console.log(projectData.ProjectItem.F1.PrincipalName)

  return {
    TuDiQuanLiRen: projectData.ProjectItem.F1.PrincipalName,
    ZuoLuo: projectData.ProjectItem.F1.Location,
    alertSave: sketchState.alertSave,
    saveIsChecked: sketchState.saveIsChecked,
    thematicMapSaveSuccess: canvasSeduce.thematicMapSaveSuccess,
    thematicMapSaveLoading: canvasSeduce.thematicMapSaveLoading,
    mapCenter: sketchState.mapCenter,
    jzdJSONData: sketchState.jzdJSONData,
    szJSONData: sketchState.szJSONData,
    jzxJSONData:sketchState.jzxJSONData,
    zdJSONData: sketchState.zdJSONData,
    zjJSONData: sketchState.zjJSONData
  };
};

const mapDispatchToProps = dispatch => {
  return {
    onSaveAlertClose: () => {
      dispatch({
        type: "saveAlertClose"
      });
    },

    onSaveThematicMapClick: () => {
      dispatch({
        type: "SAVE_THEMATICMAP_CLICK"
      });

      console.log(findDOMNode(thematicMapDOM))
      html2canvas(findDOMNode(thematicMapDOM)).then(function(canvas) {
        console.log(canvas.toDataURL())
        const ThematicMapDataURL = canvas.toDataURL();
        const ThematicMapDataLoad = ThematicMapDataURL.slice(
          ThematicMapDataURL.indexOf(",") + 1
        );
        fetch(appConfig.fileServiceRootPath + "/project/savepicture", {
          method: "POST",
          body: ThematicMapDataLoad
        })
          .then(response => response.json())
          .then(json => {
            dispatch({
              type: "SUCCESS_SAVE_THEMATICMAP_CLICK"
            });
            setTimeout(() => {
              dispatch({
                type: "RESTARE_SUCCESS_SAVE_THEMATICMAP_CLICK"
              });
            }, 1000);
            console.log(json);
          })
          .catch(err => {
            console.log(err);
          });
      })

      // const ThematicMapDataURL = thematicMap.toDataURL();
      // const ThematicMapDataLoad = ThematicMapDataURL.slice(
      //   ThematicMapDataURL.indexOf(",") + 1
      // );
      // console.log(ThematicMapDataLoad);

      // fetch(appConfig.fileServiceRootPath + "/project/savepicture", {
      //   method: "POST",
      //   body: ThematicMapDataLoad
      // })
      //   .then(response => response.json())
      //   .then(json => {
      //     dispatch({
      //       type: "SUCCESS_SAVE_THEMATICMAP_CLICK"
      //     });
      //     setTimeout(() => {
      //       dispatch({
      //         type: "RESTARE_SUCCESS_SAVE_THEMATICMAP_CLICK"
      //       });
      //     }, 1000);
      //     console.log(json);
      //   })
      //   .catch(err => {
      //     console.log(err);
      //   });
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(
  withStyles(styles, { name: "ThematicMap" })(ThematicMap)
);

//reducer
const CanvasReduce = (
  state = {
    thematicMapImg: ImageData,
    thematicMapSaveSuccess: false,
    thematicMapSaveLoading: false
  },
  action
) => {
  let newState = JSON.parse(JSON.stringify(state));

  switch (action.type) {
    case "SAVE_THEMATICMAP_CLICK":
      if (!state.thematicMapSaveLoading) {
        newState.thematicMapSaveLoading = true;
      }
      return { ...state, ...newState };
    case "SUCCESS_SAVE_THEMATICMAP_CLICK":
      newState.thematicMapSaveLoading = false;
      newState.thematicMapSaveSuccess = true;
      return { ...state, ...newState };
    case "RESTARE_SUCCESS_SAVE_THEMATICMAP_CLICK":
      newState.thematicMapSaveSuccess = false;
      return { ...state, ...newState };
    default:
      return { ...state };
  }
};
RootReducer.merge(CanvasReduce);
<|endoftext|>


<commit_before>var Scrapper = require('./scrapper');
var cheerio = require('cheerio');

var scrapper = new Scrapper('coolrom.com');

parser = {}

parser.getPlatforms = function(callback) {
	var $;
	scrapper.getPlatforms(function (err, resp) {
		if (err) return callback(err);
		$ = cheerio.load(resp);

		var parsed = $('font a:not([class], [title], [target], [href^="/"][href$=".php"])')

		var platforms = [];

		parsed.map(function (index, item) {

			platforms.push({
				code: item.attribs.href.replace('/roms/', '').replace('/', ''),
				name: item.children[0].data
			});

		});

		callback(null, platforms);

	});

};

parser.searchRom = function(query, system, callback) {
	var $;
	scrapper.searchRom(query, system, function (err, resp) {
		if (err) return callback(err);

		$ = cheerio.load(resp);

		var roms = [];

		var romsParsed = $('font[size=2] a[href^="/roms/"][href$=".php"]');

		romsParsed.map(function (index, item) {

			var splitedUrl = item.attribs.href.split('/');

			roms.push({
				id: splitedUrl[3],
				platform: splitedUrl[2],
				name: item.children[0].data
			});

		});

		callback(err, roms);
	});

};

parser.getRomByIdAndPlatform = function(id, platform, callback) {
	var $;
	scrapper.getRomByIdAndPlatform(id, platform, function (err, resp) {

		if (err) return callback(err);

		$ = cheerio.load(resp);

		var screenshotsRaw = $('img[src^="http://coolrom.com/screenshots/"][src$=".jpg"]').slice(0, 2);
		var screenshots = [];
		var name = $('title')[0].children[0].data.split(' ROM')[0]
		//var name = //$('div b')[1].innerHTML.split('» ')[this.length]

		screenshotsRaw.map(function (index,  item) {
			screenshots.push(item.attribs.src);
		});

		callback(err, {
			id: id,
			platform: platform,
			screenshots: screenshots,
			name: name
		});

	});

};

parser.getRomDownloadLink = function(id, callback) {
	var $;
	scrapper.getRomDownloadLink(id, function (err, body, resp){
		if (err) return callback(err);
		var link = body.match(/(http:\/\/)+(fs)+[0-9]+(\.coolrom\.com)+[^\,\'\\]{0,}/g)[1];
		callback(err, link);
	});
};

parser.getFiltersByPlatform = function(platform, callback) {
	var $;
	scrapper.getRomsByPlatform(platform, function (err, resp){
		if (err) return callback(err);
		$ = cheerio.load(resp);
		var tags = $('a[href^="/roms/'+platform+'/"][href$="/"]')
		var filter = [];

		tags.map(function (index, item){
			var tag = item.attribs.href.split('/')[3];
			if (tag == '') return;
			var name = item.children[0].data;
			filter.push({code: tag, name: name});
		});

		callback(err, filter);
	});

};

parser.getRomsByPlatformAndFilter = function(platform, filter, callback) {
	var $;
	scrapper.getRomsByPlatformAndFilter(platform, filter, function (err, resp){
		if (err) return callback(err);

		$ = cheerio.load(resp);

		var roms = [];

		var romsParsed = $('a[href^="/roms/"][href$=".php"]');

		romsParsed.map(function (index, item){

			var splitedUrl = item.attribs.href.split('/');

			roms.push({
				id: splitedUrl[3],
				platform: splitedUrl[2],
				name: item.children[0].data
			});

		});

		callback(err, roms);
	});
};

module.exports = parser<commit_msg>Quickfix for new URL structure in Coolrom's direct download link<commit_after>var Scrapper = require('./scrapper');
var cheerio = require('cheerio');

var scrapper = new Scrapper('coolrom.com');

parser = {}

parser.getPlatforms = function(callback) {
	var $;
	scrapper.getPlatforms(function (err, resp) {
		if (err) return callback(err);
		$ = cheerio.load(resp);

		var parsed = $('font a:not([class], [title], [target], [href^="/"][href$=".php"])')

		var platforms = [];

		parsed.map(function (index, item) {

			platforms.push({
				code: item.attribs.href.replace('/roms/', '').replace('/', ''),
				name: item.children[0].data
			});

		});

		callback(null, platforms);

	});

};

parser.searchRom = function(query, system, callback) {
	var $;
	scrapper.searchRom(query, system, function (err, resp) {
		if (err) return callback(err);

		$ = cheerio.load(resp);

		var roms = [];

		var romsParsed = $('font[size=2] a[href^="/roms/"][href$=".php"]');

		romsParsed.map(function (index, item) {

			var splitedUrl = item.attribs.href.split('/');

			roms.push({
				id: splitedUrl[3],
				platform: splitedUrl[2],
				name: item.children[0].data
			});

		});

		callback(err, roms);
	});

};

parser.getRomByIdAndPlatform = function(id, platform, callback) {
	var $;
	scrapper.getRomByIdAndPlatform(id, platform, function (err, resp) {

		if (err) return callback(err);

		$ = cheerio.load(resp);

		var screenshotsRaw = $('img[src^="http://coolrom.com/screenshots/"][src$=".jpg"]').slice(0, 2);
		var screenshots = [];
		var name = $('title')[0].children[0].data.split(' ROM')[0]
		//var name = //$('div b')[1].innerHTML.split('» ')[this.length]

		screenshotsRaw.map(function (index,  item) {
			screenshots.push(item.attribs.src);
		});

		callback(err, {
			id: id,
			platform: platform,
			screenshots: screenshots,
			name: name
		});

	});

};

parser.getRomDownloadLink = function(id, callback) {
	var $;
	scrapper.getRomDownloadLink(id, function (err, body, resp){
		if (err) return callback(err);
		var link = body.match(/(http:\/\/)+(.*\.coolrom.com\/dl\/.*\/.*\/.*\/")/g)[0];
		link = link.substring(0, link.length - 1)
		callback(err, link);
	});
};

parser.getFiltersByPlatform = function(platform, callback) {
	var $;
	scrapper.getRomsByPlatform(platform, function (err, resp){
		if (err) return callback(err);
		$ = cheerio.load(resp);
		var tags = $('a[href^="/roms/'+platform+'/"][href$="/"]')
		var filter = [];

		tags.map(function (index, item){
			var tag = item.attribs.href.split('/')[3];
			if (tag == '') return;
			var name = item.children[0].data;
			filter.push({code: tag, name: name});
		});

		callback(err, filter);
	});

};

parser.getRomsByPlatformAndFilter = function(platform, filter, callback) {
	var $;
	scrapper.getRomsByPlatformAndFilter(platform, filter, function (err, resp){
		if (err) return callback(err);

		$ = cheerio.load(resp);

		var roms = [];

		var romsParsed = $('a[href^="/roms/"][href$=".php"]');

		romsParsed.map(function (index, item){

			var splitedUrl = item.attribs.href.split('/');

			roms.push({
				id: splitedUrl[3],
				platform: splitedUrl[2],
				name: item.children[0].data
			});

		});

		callback(err, roms);
	});
};

module.exports = parser
<|endoftext|>


<commit_before>var http = require('http');
var express = require('express');
var app = express();
var server = http.Server(app);
var io = require('socket.io')(server);

app.get('/', function(req, res) {
    res.send('test');
});

app.set('port', 9000);

server.listen(app.get('port'), function() {
    console.log('Listen port ' + app.get('port'));
});

io.on('connection', function(socket) {

    var token = socket.id;
    console.log('token', token);
    socket.join(token);

    socket.on('location', function(data) {

        console.log(data);

        io.to(token).emit('res', {
            data: 'get your room' + token
        });
    });
});<commit_msg>fixed bug<commit_after>var http = require('http');
var express = require('express');
var app = express();
var server = http.Server(app);
var io = require('socket.io')(server);

app.get('/', function(req, res) {
    res.send('test');
});

app.set('port', 9000);

server.listen(app.get('port'), function() {
    console.log('Listen port ' + app.get('port'));
});

io.on('connection', function(socket) {

    var token = socket.id;
    console.log('token', token);
    socket.join(token);

    socket.on('location', function(data) {

        console.log(data);

        io.to(token).emit('res', {
            data: 'get your room : ' + token
        });
    });
});<|endoftext|>