<commit_before>/*
Copyright 2011 Newcastle University

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
Numbas.queueScript('scripts/jme-variables.js',['jme','util'],function() {

var jme = Numbas.jme;
var util = Numbas.util;

jme.variables = {

	makeJMEFunction: function(fn,scope) {
		fn.tree = jme.compile(fn.definition,scope,true);
		return function(args,scope) {
			var oscope = scope;
			scope = new jme.Scope(scope);

			for(var j=0;j<args.length;j++)
			{
				scope.variables[fn.paramNames[j]] = args[j];
			}
			return jme.evaluate(this.tree,scope);
		}
	},

	makeJavascriptFunction: function(fn,scope) {
		var preamble='fn.jfn=(function('+fn.paramNames.join(',')+'){';
		var math = Numbas.math;
		var util = Numbas.util;
		var jfn = eval(preamble+fn.definition+'})');
		return function(args,scope) {
			args = args.map(function(a){return jme.unwrapValue(a)});
			try {
				var val = jfn.apply(this,args);
				if(val===undefined) {
					throw(new Numbas.Error('jme.user javascript.returned undefined',fn.name));
				}
				val = jme.wrapValue(val);
				if(!val.type)
					val = new fn.outcons(val);
				return val;
			}
			catch(e)
			{
				throw(new Numbas.Error('jme.user javascript.error',fn.name,e.message));
			}
		}
	},

	makeFunction: function(tmpfn,scope) {
		var intype = [],
			paramNames = [];

		tmpfn.parameters.map(function(p) {
			intype.push(jme.types[p.type]);
			paramNames.push(p.name);
		});

		var outcons = jme.types[tmpfn.outtype];

		var fn = new jme.funcObj(tmpfn.name,intype,outcons,null,true);

		fn.outcons = outcons;
		fn.intype = intype;
		fn.paramNames = paramNames;
		fn.definition = tmpfn.definition;
		fn.name = tmpfn.name;
		fn.language = tmpfn.language;

		switch(fn.language)
		{
		case 'jme':
			fn.evaluate = jme.variables.makeJMEFunction(fn,scope);
			break;
		case 'javascript':
			fn.evaluate = jme.variables.makeJavascriptFunction(fn,scope);
			break;
		}
		return fn
	},

	makeFunctions: function(tmpFunctions,scope)
	{
		scope = new jme.Scope(scope);
		var functions = scope.functions;
		var tmpFunctions2 = [];
		for(var i=0;i<tmpFunctions.length;i++)
		{
			var cfn = jme.variables.makeFunction(tmpFunctions[i],scope);

			if(functions[cfn.name]===undefined)
				functions[cfn.name] = [];
			functions[cfn.name].push(cfn);

		}
		return functions;
	},

	computeVariable: function(name,todo,scope,path)
	{
		if(scope.variables[name]!==undefined)
			return scope.variables[name];

		if(path===undefined)
			path=[];

		if(path.contains(name))
		{
			throw(new Numbas.Error('jme.variables.circular reference',name,path));
		}

		var v = todo[name];

		if(v===undefined)
			throw(new Numbas.Error('jme.variables.variable not defined',name));

		//work out dependencies
		for(var i=0;i<v.vars.length;i++)
		{
			var x=v.vars[i];
			if(scope.variables[x]===undefined)
			{
				var newpath = path.slice(0);
				newpath.splice(0,0,name);
				try {
					jme.variables.computeVariable(x,todo,scope,newpath);
				}
				catch(e) {
					throw(new Numbas.Error('jme.variables.error computing dependency',x));
				}
			}
		}

		scope.variables[name] = jme.evaluate(v.tree,scope);
		return scope.variables[name];
	},

	makeVariables: function(todo,scope)
	{
		scope = new jme.Scope(scope);
		for(var x in todo)
		{
			jme.variables.computeVariable(x,todo,scope);
		}
		return scope.variables;
	},

	DOMcontentsubvars: function(element, scope) {
		if($.nodeName(element,'iframe'))
			return element;

		$(element).contents().each(function() {
			if(this.nodeType==(this.TEXT_NODE || 3)) {
				var selector = $(this);
				var str = this.nodeValue;
				var bits = util.contentsplitbrackets(str);	//split up string by TeX delimiters. eg "let $X$ = \[expr\]" becomes ['let ','$','X','$',' = ','\[','expr','\]','']
				var i=0;
				var l = bits.length;
				for(var i=0; i<l; i+=4) {
					var textsubs = jme.variables.DOMsubvars(bits[i],scope,this.ownerDocument);
					for(var j=0;j<textsubs.length;j++) {
						selector.before(textsubs[j]);
					}
					var n = this.ownerDocument.createTextNode((bits[i+1]||'')+jme.texsubvars(bits[i+2]||'',scope)+(bits[i+3]||''));
					selector.before(n);
				}
				selector.remove();
			} else {
				jme.variables.DOMcontentsubvars(this,scope);
			}
		});
		return element;
	},

	DOMsubvars: function(str,scope,doc) {
		doc = doc || document;
		var bits = util.splitbrackets(str,'{','}');

		if(bits.length==1)
			return [str];

		var out = [];
		for(var i=0; i<bits.length; i++)
		{
			if(i % 2)
			{
				var v = jme.evaluate(jme.compile(bits[i],scope),scope);
				switch(v.type){
				case 'html':
					v = v.value;
					break;
				case 'number':
					v = Numbas.math.niceNumber(v.value);
					break;
				case 'string':
					v = v.value.replace(/\\([{}])/g,'$1');
					break;
				default:
					v = jme.display.treeToJME({tok:v});
				}
			}
			else
			{
				v = bits[i];
			}
			if(typeof v == 'string') {
				if(out.length>0 && typeof out[out.length-1]=='string')
					out[out.length-1]+=v;
				else
					out.push(v);
			}
			else {
				out.push(v);
			}
		}
		for(var i=0;i<out.length;i++) {
			if(typeof out[i] == 'string') {
				var d = document.createElement('div');
				d.innerHTML = out[i];
				d = importNode(doc,d,true);
				out[i] = $(d).contents();
			}
		}
		return out;
	}
};

// cross-browser importNode from http://www.alistapart.com/articles/crossbrowserscripting/
// because IE8 is completely mentile and won't let you copy nodes between documents in anything approaching a reasonable way
function importNode(doc,node,allChildren) {
	var ELEMENT_NODE = 1;
	var TEXT_NODE = 3;
	var CDATA_SECTION_NODE = 4;
	var COMMENT_NODE = 8;

	switch (node.nodeType) {
		case ELEMENT_NODE:
			var newNode = doc.createElement(node.nodeName);
			var il;
			/* does the node have any attributes to add? */
			if (node.attributes && (il=node.attributes.length) > 0) {
				for (var i = 0; i < il; i++)
					newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i].nodeName));
			}
			/* are we going after children too, and does the node have any? */
			if (allChildren && node.childNodes && (il=node.childNodes.length) > 0) {
				for (var i = 0; i<il; i++)
					newNode.appendChild(importNode(doc,node.childNodes[i], allChildren));
			}
			return newNode;
		case TEXT_NODE:
		case CDATA_SECTION_NODE:
			return doc.createTextNode(node.nodeValue);
		case COMMENT_NODE:
			return doc.createComment(node.nodeValue);
	}
};

});
<commit_msg>newline after javascript function definition<commit_after>/*
Copyright 2011 Newcastle University

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
Numbas.queueScript('scripts/jme-variables.js',['jme','util'],function() {

var jme = Numbas.jme;
var util = Numbas.util;

jme.variables = {

	makeJMEFunction: function(fn,scope) {
		fn.tree = jme.compile(fn.definition,scope,true);
		return function(args,scope) {
			var oscope = scope;
			scope = new jme.Scope(scope);

			for(var j=0;j<args.length;j++)
			{
				scope.variables[fn.paramNames[j]] = args[j];
			}
			return jme.evaluate(this.tree,scope);
		}
	},

	makeJavascriptFunction: function(fn,scope) {
		var preamble='fn.jfn=(function('+fn.paramNames.join(',')+'){';
		var math = Numbas.math;
		var util = Numbas.util;
		var jfn = eval(preamble+fn.definition+'\n})');
		return function(args,scope) {
			args = args.map(function(a){return jme.unwrapValue(a)});
			try {
				var val = jfn.apply(this,args);
				if(val===undefined) {
					throw(new Numbas.Error('jme.user javascript.returned undefined',fn.name));
				}
				val = jme.wrapValue(val);
				if(!val.type)
					val = new fn.outcons(val);
				return val;
			}
			catch(e)
			{
				throw(new Numbas.Error('jme.user javascript.error',fn.name,e.message));
			}
		}
	},

	makeFunction: function(tmpfn,scope) {
		var intype = [],
			paramNames = [];

		tmpfn.parameters.map(function(p) {
			intype.push(jme.types[p.type]);
			paramNames.push(p.name);
		});

		var outcons = jme.types[tmpfn.outtype];

		var fn = new jme.funcObj(tmpfn.name,intype,outcons,null,true);

		fn.outcons = outcons;
		fn.intype = intype;
		fn.paramNames = paramNames;
		fn.definition = tmpfn.definition;
		fn.name = tmpfn.name;
		fn.language = tmpfn.language;

		switch(fn.language)
		{
		case 'jme':
			fn.evaluate = jme.variables.makeJMEFunction(fn,scope);
			break;
		case 'javascript':
			fn.evaluate = jme.variables.makeJavascriptFunction(fn,scope);
			break;
		}
		return fn
	},

	makeFunctions: function(tmpFunctions,scope)
	{
		scope = new jme.Scope(scope);
		var functions = scope.functions;
		var tmpFunctions2 = [];
		for(var i=0;i<tmpFunctions.length;i++)
		{
			var cfn = jme.variables.makeFunction(tmpFunctions[i],scope);

			if(functions[cfn.name]===undefined)
				functions[cfn.name] = [];
			functions[cfn.name].push(cfn);

		}
		return functions;
	},

	computeVariable: function(name,todo,scope,path)
	{
		if(scope.variables[name]!==undefined)
			return scope.variables[name];

		if(path===undefined)
			path=[];

		if(path.contains(name))
		{
			throw(new Numbas.Error('jme.variables.circular reference',name,path));
		}

		var v = todo[name];

		if(v===undefined)
			throw(new Numbas.Error('jme.variables.variable not defined',name));

		//work out dependencies
		for(var i=0;i<v.vars.length;i++)
		{
			var x=v.vars[i];
			if(scope.variables[x]===undefined)
			{
				var newpath = path.slice(0);
				newpath.splice(0,0,name);
				try {
					jme.variables.computeVariable(x,todo,scope,newpath);
				}
				catch(e) {
					throw(new Numbas.Error('jme.variables.error computing dependency',x));
				}
			}
		}

		scope.variables[name] = jme.evaluate(v.tree,scope);
		return scope.variables[name];
	},

	makeVariables: function(todo,scope)
	{
		scope = new jme.Scope(scope);
		for(var x in todo)
		{
			jme.variables.computeVariable(x,todo,scope);
		}
		return scope.variables;
	},

	DOMcontentsubvars: function(element, scope) {
		if($.nodeName(element,'iframe'))
			return element;

		$(element).contents().each(function() {
			if(this.nodeType==(this.TEXT_NODE || 3)) {
				var selector = $(this);
				var str = this.nodeValue;
				var bits = util.contentsplitbrackets(str);	//split up string by TeX delimiters. eg "let $X$ = \[expr\]" becomes ['let ','$','X','$',' = ','\[','expr','\]','']
				var i=0;
				var l = bits.length;
				for(var i=0; i<l; i+=4) {
					var textsubs = jme.variables.DOMsubvars(bits[i],scope,this.ownerDocument);
					for(var j=0;j<textsubs.length;j++) {
						selector.before(textsubs[j]);
					}
					var n = this.ownerDocument.createTextNode((bits[i+1]||'')+jme.texsubvars(bits[i+2]||'',scope)+(bits[i+3]||''));
					selector.before(n);
				}
				selector.remove();
			} else {
				jme.variables.DOMcontentsubvars(this,scope);
			}
		});
		return element;
	},

	DOMsubvars: function(str,scope,doc) {
		doc = doc || document;
		var bits = util.splitbrackets(str,'{','}');

		if(bits.length==1)
			return [str];

		var out = [];
		for(var i=0; i<bits.length; i++)
		{
			if(i % 2)
			{
				var v = jme.evaluate(jme.compile(bits[i],scope),scope);
				switch(v.type){
				case 'html':
					v = v.value;
					break;
				case 'number':
					v = Numbas.math.niceNumber(v.value);
					break;
				case 'string':
					v = v.value.replace(/\\([{}])/g,'$1');
					break;
				default:
					v = jme.display.treeToJME({tok:v});
				}
			}
			else
			{
				v = bits[i];
			}
			if(typeof v == 'string') {
				if(out.length>0 && typeof out[out.length-1]=='string')
					out[out.length-1]+=v;
				else
					out.push(v);
			}
			else {
				out.push(v);
			}
		}
		for(var i=0;i<out.length;i++) {
			if(typeof out[i] == 'string') {
				var d = document.createElement('div');
				d.innerHTML = out[i];
				d = importNode(doc,d,true);
				out[i] = $(d).contents();
			}
		}
		return out;
	}
};

// cross-browser importNode from http://www.alistapart.com/articles/crossbrowserscripting/
// because IE8 is completely mentile and won't let you copy nodes between documents in anything approaching a reasonable way
function importNode(doc,node,allChildren) {
	var ELEMENT_NODE = 1;
	var TEXT_NODE = 3;
	var CDATA_SECTION_NODE = 4;
	var COMMENT_NODE = 8;

	switch (node.nodeType) {
		case ELEMENT_NODE:
			var newNode = doc.createElement(node.nodeName);
			var il;
			/* does the node have any attributes to add? */
			if (node.attributes && (il=node.attributes.length) > 0) {
				for (var i = 0; i < il; i++)
					newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i].nodeName));
			}
			/* are we going after children too, and does the node have any? */
			if (allChildren && node.childNodes && (il=node.childNodes.length) > 0) {
				for (var i = 0; i<il; i++)
					newNode.appendChild(importNode(doc,node.childNodes[i], allChildren));
			}
			return newNode;
		case TEXT_NODE:
		case CDATA_SECTION_NODE:
			return doc.createTextNode(node.nodeValue);
		case COMMENT_NODE:
			return doc.createComment(node.nodeValue);
	}
};

});
<|endoftext|>


<commit_before>var controller = Ember.Controller.extend({
  needs: ['tasks', 'activityLog', 'configure'],
  user: null,
  urls: {
    login: '/login/google-oauth2/',
    logout: '/logout/',
    about: '/about/',
    ca_certificate: '/api/v1/user/ca-certificate/',
    my_certificate: '/api/v1/user/my-certificate/',
    my_key: '/api/v1/user/my-key/',
    taskrc_extras: '/api/v1/user/taskrc/',
    taskd_settings: '/api/v1/user/configure-taskd/',
    taskd_reset: '/api/v1/user/reset-taskd-configuration/',
    twilio_integration: '/api/v1/user/twilio-integration/',
    tos_accept: '/api/v1/user/tos-accept/',
    clear_task_data: '/api/v1/user/clear-task-data/',
    set_colorscheme: '/api/v1/user/colorscheme/',
    enable_sync: '/api/v1/user/enable-sync/',
    configure_pebble_cards: '/api/v1/user/pebble-cards-config/',
    configure_feed: '/api/v1/user/feed-config/',
    refresh: '/api/v1/task/refresh/',
    status_feed: '/status/',
    feed_url: null,
    sms_url: null,
    pebble_card_url: null,
  },
  taskUpdateStreamEnabled: function() {
    return this.get('controllers.configure.taskUpdateStreamEnabled');
  }.property(),
  update_user_info: function() {
    this.set(
      'user',
      JSON.parse(
        $.ajax(
          {
            url: '/api/v1/user/status/',
            async: false,
            dataType: 'json'
          }
        ).responseText
      )
    );
    this.updateColorscheme();
    if(this.get('user').logged_in){
      Raven.setUser({
        email: this.get('user').email,
        id: this.get('user').uid,
        username: this.get('user').username
      });
    } else {
      Raven.setUser();
    }
    this.set('urls.feed_url', this.get('user').feed_url);
    this.set('urls.sms_url', this.get('user').sms_url);
    this.set('urls.pebble_card_url', this.get('user').pebble_card_url);
    this.set('statusUpdaterHead', this.get('user').repository_head);
  },
  handleError: function(reason, tsn) {
    if (reason.status == 401) {
      alert(
          [
            "We're sorry, but your session appears to have expired.\n",
            "Press OK log-in again.",
          ].join('\n')
      );
      window.location = this.get('urls.login');
    }
  },
  init: function(){
    var self = this;

    // Set up error reporting
    Ember.onerror = reportError;
    Ember.RSVP.configure('onerror', reportError);

    // Fetch user information
    this.update_user_info();

    // Ensure that we always add the CSRF token
    $.ajaxSetup({
      headers: {
        'X-CSRFToken': this.getCookie('csrftoken')
      }
    });

    // Adding FastClick
    window.addEventListener('load', function() {
      FastClick.attach(document.body);
    }, false);

    // Set up the event stream
    if(this.get('taskUpdateStreamEnabled')) {
      this.set('statusUpdaterLog', []);
      this.startEventStream();
      setInterval(this.checkStatusUpdater.bind(this), 500);
    }
    setInterval(this.checkLastUpdated.bind(this), 2000);
  },
  checkLastUpdated: function() {
    var lastHeartbeat = this.get('statusUpdaterHeartbeat');
    var lastRefresh = this.get('pollingRefresh');
    if (!lastRefresh) {
      lastRefresh = new Date();
      this.set('pollingRefresh', lastRefresh);
    }
    var interval = 60 * 2.5 * 1000; // 2.5 mins
    if((new Date() - Math.max(lastRefresh, lastHeartbeat | null)) > interval) {
      this.set('pollingRefresh', new Date());
      this.send('refresh');
    }
  },
  checkStatusUpdater: function() {
    var statusUpdater = this.get('statusUpdater');
    var connected = this.get('taskUpdateStreamConnected');
    var now = new Date();
    var lastHeartbeat = this.get('statusUpdaterHeartbeat');
    var flatineDelay = 19 * 1000; // 19 seconds
    var postDisconnectDelay = 5 * 1000;  // 5 seconds
    if (!statusUpdater) {
      return;
    }
    if (!lastHeartbeat) {
      lastHeartbeat = now;
      this.set('statusUpdaterHeartbeat', lastHeartbeat);
    }
    if (
      (statusUpdater.readyState != window.EventSource.OPEN) ||
      ((now - lastHeartbeat) > flatlineDelay)
    ) {
      this.set('taskUpdateStreamConnected', false);
      this.set('statusUpdaterErrorred', true);
      var since = this.get('taskUpdateStreamConnectionLost');
      if (! since) {
        this.set('taskUpdateStreamConnectionLost', now);
      } else if(now - since > postDisconnectDelay) {
        statusUpdater.close();
        var log = this.get('statusUpdaterLog');
        log.pushObject(
            [now, 'Connection appears to be disconnected']
        );
        this.set('statusUpdaterErrorred', true);
        this.set('taskUpdateStreamConnectionLost', null);
        this.get('startEventStream').bind(this)();
      }
    } else if (
      (statusUpdater.readyState == window.EventSource.OPEN) &&
      !connected
    ) {
      this.set('taskUpdateStreamConnected', true);
      this.set('statusUpdaterErrorred', false);
    }
  },
  startEventStream: function() {
    var head = this.get('statusUpdaterHead');
    var log = this.get('statusUpdaterLog');
    this.set('statusUpdaterHeartbeat', new Date());
    log.pushObject(
      [new Date(), 'Starting with HEAD ' + head]
    );
    var statusUpdater = this.get('statusUpdater');
    if (
      this.get('taskUpdateStreamEnabled') &&
      (!statusUpdater || statusUpdater.readyState == window.EventSource.CLOSED)
    ){
      url = this.get('urls.status_feed');
      if(head && typeof(head) == 'string') {
        url = url + "?head=" +  head;
      }
      statusUpdater = new window.EventSource(url);
      this.bindStatusActions(statusUpdater);
      this.set('statusUpdater', statusUpdater);
      this.set('statusUpdaterHead', head);
    } else {
      this.set('taskUpdateStreamConnected', false);
    }
  },
  eventStreamError: function(evt) {
    this.get('startEventStream').bind(this)();
  },
  updateColorscheme: function() {
    var scheme = this.get('user').colorscheme;
    $("#colorscheme").attr('href', '/static/colorschemes/' + scheme + '.css');
  },
  bindStatusActions: function(updater) {
    for (var key in this.get('statusActions')) {
      updater.addEventListener(key, this.get('statusActions')[key].bind(this));
    }
    updater.addEventListener(
      'error',
      this.get('eventStreamError').bind(this)
    );
  },
  statusActions: {
    'task_changed': function(evt) {
      Ember.run.once(this, function(){
        this.store.find('task', evt.data).then(function(record){
          if (record.get('isLoaded') && (!record.get('isDirty') && !record.get('isSaving'))) {
            record.reload();
          }
        });
      });
    },
    'head_changed': function(evt) {
      var statusUpdater = this.get('statusUpdater');
      if (statusUpdater) {
        statusUpdater.close();
        this.get('startEventStream').bind(this)();
      }
      this.set('statusUpdaterHead', evt.data);
      try {
        this.store.find('activityLog').update();
      } catch(e) {
        // Pass
      }
    },
    'error_logged': function(evt) {
      $.growl.error({
        title: 'Error',
        message: evt.data
      });
    },
    'heartbeat': function(evt) {
      this.set('statusUpdaterHeartbeat', new Date());
      var heartbeat_data = JSON.parse(evt.data);
      this.set('user.sync_enabled', heartbeat_data.sync_enabled);
    }
  },
  isSmallScreen: function() {
    return $(document).width() <= 700;
  },
  getCookie: function(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) == (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  },
  actions: {
    refresh: function(){
      var self = this;
      $.ajax({
        url: this.get('urls.refresh'),
        dataType: 'json',
        data: {
          head: this.get('statusUpdaterHead'),
        },
        success: function(data) {
          for(var i = 0; i < data.messages.length; i++) {
            var msg = data.messages[i];
            self.get('statusActions')[msg.action].bind(self)({data: msg.body});
          }
        }
      });
    },
    home: function(){
      window.location = '/';
    },
    login: function(){
      window.location = this.get('urls.login');
    },
    logout: function(){
      window.location = this.get('urls.logout');
    }
  }
});

module.exports = controller;
<commit_msg>Spell things properly.<commit_after>var controller = Ember.Controller.extend({
  needs: ['tasks', 'activityLog', 'configure'],
  user: null,
  urls: {
    login: '/login/google-oauth2/',
    logout: '/logout/',
    about: '/about/',
    ca_certificate: '/api/v1/user/ca-certificate/',
    my_certificate: '/api/v1/user/my-certificate/',
    my_key: '/api/v1/user/my-key/',
    taskrc_extras: '/api/v1/user/taskrc/',
    taskd_settings: '/api/v1/user/configure-taskd/',
    taskd_reset: '/api/v1/user/reset-taskd-configuration/',
    twilio_integration: '/api/v1/user/twilio-integration/',
    tos_accept: '/api/v1/user/tos-accept/',
    clear_task_data: '/api/v1/user/clear-task-data/',
    set_colorscheme: '/api/v1/user/colorscheme/',
    enable_sync: '/api/v1/user/enable-sync/',
    configure_pebble_cards: '/api/v1/user/pebble-cards-config/',
    configure_feed: '/api/v1/user/feed-config/',
    refresh: '/api/v1/task/refresh/',
    status_feed: '/status/',
    feed_url: null,
    sms_url: null,
    pebble_card_url: null,
  },
  taskUpdateStreamEnabled: function() {
    return this.get('controllers.configure.taskUpdateStreamEnabled');
  }.property(),
  update_user_info: function() {
    this.set(
      'user',
      JSON.parse(
        $.ajax(
          {
            url: '/api/v1/user/status/',
            async: false,
            dataType: 'json'
          }
        ).responseText
      )
    );
    this.updateColorscheme();
    if(this.get('user').logged_in){
      Raven.setUser({
        email: this.get('user').email,
        id: this.get('user').uid,
        username: this.get('user').username
      });
    } else {
      Raven.setUser();
    }
    this.set('urls.feed_url', this.get('user').feed_url);
    this.set('urls.sms_url', this.get('user').sms_url);
    this.set('urls.pebble_card_url', this.get('user').pebble_card_url);
    this.set('statusUpdaterHead', this.get('user').repository_head);
  },
  handleError: function(reason, tsn) {
    if (reason.status == 401) {
      alert(
          [
            "We're sorry, but your session appears to have expired.\n",
            "Press OK log-in again.",
          ].join('\n')
      );
      window.location = this.get('urls.login');
    }
  },
  init: function(){
    var self = this;

    // Set up error reporting
    Ember.onerror = reportError;
    Ember.RSVP.configure('onerror', reportError);

    // Fetch user information
    this.update_user_info();

    // Ensure that we always add the CSRF token
    $.ajaxSetup({
      headers: {
        'X-CSRFToken': this.getCookie('csrftoken')
      }
    });

    // Adding FastClick
    window.addEventListener('load', function() {
      FastClick.attach(document.body);
    }, false);

    // Set up the event stream
    if(this.get('taskUpdateStreamEnabled')) {
      this.set('statusUpdaterLog', []);
      this.startEventStream();
      setInterval(this.checkStatusUpdater.bind(this), 500);
    }
    setInterval(this.checkLastUpdated.bind(this), 2000);
  },
  checkLastUpdated: function() {
    var lastHeartbeat = this.get('statusUpdaterHeartbeat');
    var lastRefresh = this.get('pollingRefresh');
    if (!lastRefresh) {
      lastRefresh = new Date();
      this.set('pollingRefresh', lastRefresh);
    }
    var interval = 60 * 2.5 * 1000; // 2.5 mins
    if((new Date() - Math.max(lastRefresh, lastHeartbeat | null)) > interval) {
      this.set('pollingRefresh', new Date());
      this.send('refresh');
    }
  },
  checkStatusUpdater: function() {
    var statusUpdater = this.get('statusUpdater');
    var connected = this.get('taskUpdateStreamConnected');
    var now = new Date();
    var lastHeartbeat = this.get('statusUpdaterHeartbeat');
    var flatlineDelay = 19 * 1000; // 19 seconds
    var postDisconnectDelay = 5 * 1000;  // 5 seconds
    if (!statusUpdater) {
      return;
    }
    if (!lastHeartbeat) {
      lastHeartbeat = now;
      this.set('statusUpdaterHeartbeat', lastHeartbeat);
    }
    if (
      (statusUpdater.readyState != window.EventSource.OPEN) ||
      ((now - lastHeartbeat) > flatlineDelay)
    ) {
      this.set('taskUpdateStreamConnected', false);
      this.set('statusUpdaterErrorred', true);
      var since = this.get('taskUpdateStreamConnectionLost');
      if (! since) {
        this.set('taskUpdateStreamConnectionLost', now);
      } else if(now - since > postDisconnectDelay) {
        statusUpdater.close();
        var log = this.get('statusUpdaterLog');
        log.pushObject(
            [now, 'Connection appears to be disconnected']
        );
        this.set('statusUpdaterErrorred', true);
        this.set('taskUpdateStreamConnectionLost', null);
        this.get('startEventStream').bind(this)();
      }
    } else if (
      (statusUpdater.readyState == window.EventSource.OPEN) &&
      !connected
    ) {
      this.set('taskUpdateStreamConnected', true);
      this.set('statusUpdaterErrorred', false);
    }
  },
  startEventStream: function() {
    var head = this.get('statusUpdaterHead');
    var log = this.get('statusUpdaterLog');
    this.set('statusUpdaterHeartbeat', new Date());
    log.pushObject(
      [new Date(), 'Starting with HEAD ' + head]
    );
    var statusUpdater = this.get('statusUpdater');
    if (
      this.get('taskUpdateStreamEnabled') &&
      (!statusUpdater || statusUpdater.readyState == window.EventSource.CLOSED)
    ){
      url = this.get('urls.status_feed');
      if(head && typeof(head) == 'string') {
        url = url + "?head=" +  head;
      }
      statusUpdater = new window.EventSource(url);
      this.bindStatusActions(statusUpdater);
      this.set('statusUpdater', statusUpdater);
      this.set('statusUpdaterHead', head);
    } else {
      this.set('taskUpdateStreamConnected', false);
    }
  },
  eventStreamError: function(evt) {
    this.get('startEventStream').bind(this)();
  },
  updateColorscheme: function() {
    var scheme = this.get('user').colorscheme;
    $("#colorscheme").attr('href', '/static/colorschemes/' + scheme + '.css');
  },
  bindStatusActions: function(updater) {
    for (var key in this.get('statusActions')) {
      updater.addEventListener(key, this.get('statusActions')[key].bind(this));
    }
    updater.addEventListener(
      'error',
      this.get('eventStreamError').bind(this)
    );
  },
  statusActions: {
    'task_changed': function(evt) {
      Ember.run.once(this, function(){
        this.store.find('task', evt.data).then(function(record){
          if (record.get('isLoaded') && (!record.get('isDirty') && !record.get('isSaving'))) {
            record.reload();
          }
        });
      });
    },
    'head_changed': function(evt) {
      var statusUpdater = this.get('statusUpdater');
      if (statusUpdater) {
        statusUpdater.close();
        this.get('startEventStream').bind(this)();
      }
      this.set('statusUpdaterHead', evt.data);
      try {
        this.store.find('activityLog').update();
      } catch(e) {
        // Pass
      }
    },
    'error_logged': function(evt) {
      $.growl.error({
        title: 'Error',
        message: evt.data
      });
    },
    'heartbeat': function(evt) {
      this.set('statusUpdaterHeartbeat', new Date());
      var heartbeat_data = JSON.parse(evt.data);
      this.set('user.sync_enabled', heartbeat_data.sync_enabled);
    }
  },
  isSmallScreen: function() {
    return $(document).width() <= 700;
  },
  getCookie: function(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) == (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  },
  actions: {
    refresh: function(){
      var self = this;
      $.ajax({
        url: this.get('urls.refresh'),
        dataType: 'json',
        data: {
          head: this.get('statusUpdaterHead'),
        },
        success: function(data) {
          for(var i = 0; i < data.messages.length; i++) {
            var msg = data.messages[i];
            self.get('statusActions')[msg.action].bind(self)({data: msg.body});
          }
        }
      });
    },
    home: function(){
      window.location = '/';
    },
    login: function(){
      window.location = this.get('urls.login');
    },
    logout: function(){
      window.location = this.get('urls.logout');
    }
  }
});

module.exports = controller;
<|endoftext|>


<commit_before>"use strict";
var _getSert = require("../getsert");
var generateCode = require("../../../src/utils/code-generator");
var unit = require("./unit-data-util");

class StorageDataUtil {
    getSert(input) {
        var ManagerType = require("../../../src/managers/master/storage-manager");
        return _getSert(input, ManagerType, (data) => {
            return {
                code: data.code
            };
        });
    }

    getNewData() {
        return Promise.all([unit.getTestData()])
            .then((results) => {
                var _unit= results[0];
                var Model = require('dl-models').master.Storage;

                var code = generateCode();

                var data ={
                    code : code,
                    name : `name[${code}]`,
                    description : `storage description [${code}]`,
                    unit:_unit,
                    unitId:_unit._id
                }

                return Promise.resolve(data);
            });
    }

    getRandomTestData() {
        return this.getNewData()
            .then((data) => {
                return this.getSert(data);
            });
    }

    getTestData() {
         return unit.getTestData()
            .then((data) => {
                data.code = "Storage-UT-01";
                data.name = "Storage Unit Test 01";
                data.unitId=data._id;
                data.unit=data;
                data.description = "Product untuk unit test";

                return this.getSert(data);
            });
    }

    getPackingTestData() {
        return unit.getTestData()
            .then((data) => {
                data = {
                    code: 'UT/GudangJadi01',
                    name: 'Gudang Jadi Finishing Printing',
                    description: '',
                    unitId:data._id,
                    unit:data
                };
                return this.getSert(data);
         });
    }

    getTextileInventoryTestData() {
        return unit.getTestData()
            .then((data) => {
                var data = {
                    code: 'UT/GudangTextile01',
                    name: 'Gudang Pembelian Textile',
                    description: '',
                    unitId:data._id,
                    unit:data
                };
                return this.getSert(data);
            });
    }
}
module.exports = new StorageDataUtil();
<commit_msg>fix unit test<commit_after>"use strict";
var _getSert = require("../getsert");
var generateCode = require("../../../src/utils/code-generator");
var unit = require("./unit-data-util");

class StorageDataUtil {
    getSert(input) {
        var ManagerType = require("../../../src/managers/master/storage-manager");
        return _getSert(input, ManagerType, (data) => {
            return {
                name: data.name,
                unitId: data.unit._id,
            };
        });
    }

    getNewData() {
        return Promise.all([unit.getTestData()])
            .then((results) => {
                var _unit= results[0];
                var Model = require('dl-models').master.Storage;

                var code = generateCode();

                var data ={
                    code : code,
                    name : `name[${code}]`,
                    description : `storage description [${code}]`,
                    unit:_unit,
                    unitId:_unit._id
                }

                return Promise.resolve(data);
            });
    }

    getRandomTestData() {
        return this.getNewData()
            .then((data) => {
                return this.getSert(data);
            });
    }

    getTestData() {
         return unit.getTestData()
            .then((data) => {
                data.code = "Storage-UT-01";
                data.name = "Storage Unit Test 01";
                data.unitId=data._id;
                data.unit=data;
                data.description = "Product untuk unit test";

                return this.getSert(data);
            });
    }

    getPackingTestData() {
        return unit.getTestData()
            .then((data) => {
                data = {
                    code: 'UT/GudangJadi01',
                    name: 'Gudang Jadi Finishing Printing',
                    description: '',
                    unitId:data._id,
                    unit:data
                };
                return this.getSert(data);
         });
    }

    getTextileInventoryTestData() {
        return unit.getTestData()
            .then((data) => {
                var data = {
                    code: 'UT/GudangTextile01',
                    name: 'Gudang Pembelian Textile',
                    description: '',
                    unitId:data._id,
                    unit:data
                };
                return this.getSert(data);
            });
    }
}
module.exports = new StorageDataUtil();
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.provide("erpnext.company");

frappe.ui.form.on("Company", {
	setup: function(frm) {
		erpnext.company.setup_queries(frm);
	},

	company_name: function(frm) {
		if(frm.doc.__islocal) {
			let parts = frm.doc.company_name.split();
			let abbr = $.map(parts, function (p) {
				return p? p.substr(0, 1) : null;
			}).join("");
			frm.set_value("abbr", abbr);
		}
	},

	refresh: function(frm) {
		if(frm.doc.abbr && !frm.doc.__islocal) {
			frm.set_df_property("abbr", "read_only", 1);
		}

		frm.toggle_display('address_html', !frm.doc.__islocal);
		if(!frm.doc.__islocal) {
			frappe.contacts.render_address_and_contact(frm);

			frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Company'}

			frm.toggle_enable("default_currency", (frm.doc.__onload &&
				!frm.doc.__onload.transactions_exist));

			frm.add_custom_button(__('Cost Centers'), function() {
				frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name})
			}, __("View"));

			frm.add_custom_button(__('Chart of Accounts'), function() {
				frappe.set_route('Tree', 'Account', {'company': frm.doc.name})
			}, __("View"));

			frm.add_custom_button(__('Sales Tax Template'), function() {
				frappe.set_route('List', 'Sales Taxes and Charges Template', {'company': frm.doc.name});
			}, __("View"));

			frm.add_custom_button(__('Purchase Tax Template'), function() {
				frappe.set_route('List', 'Purchase Taxes and Charges Template', {'company': frm.doc.name});
			}, __("View"));

			frm.add_custom_button(__('Default Tax Template'), function() {
				frm.trigger("make_default_tax_template");
			}, __("Make"));

			frm.page.set_inner_btn_group_as_primary(__("View"));
			frm.page.set_inner_btn_group_as_primary(__("Make"));
		}

		erpnext.company.set_chart_of_accounts_options(frm.doc);

	},

	make_default_tax_template: function(frm) {
		frm.call({
			method: "create_default_tax_template",
			doc: frm.doc,
			freeze: true,
			callback: function() {
				frappe.msgprint(__("Default tax templates for sales and purchase are created."));
			}
		})
	},

	onload_post_render: function(frm) {
		if(frm.get_field("delete_company_transactions").$input)
			frm.get_field("delete_company_transactions").$input.addClass("btn-danger");
	},

	country: function(frm) {
		erpnext.company.set_chart_of_accounts_options(frm.doc);
	},

	delete_company_transactions: function(frm) {
		frappe.verify_password(function() {
			var d = frappe.prompt({
				fieldtype:"Data",
				fieldname: "company_name",
				label: __("Please re-type company name to confirm"),
				reqd: 1,
				description: __("Please make sure you really want to delete all the transactions for this company. Your master data will remain as it is. This action cannot be undone.")
			},
			function(data) {
				if(data.company_name !== frm.doc.name) {
					frappe.msgprint("Company name not same");
					return;
				}
				frappe.call({
					method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
					args: {
						company_name: data.company_name
					},
					freeze: true,
					callback: function(r, rt) {
						if(!r.exc)
							frappe.msgprint(__("Successfully deleted all transactions related to this company!"));
					},
					onerror: function() {
						frappe.msgprint(__("Wrong Password"));
					}
				});
			},
			__("Delete all the Transactions for this Company"), __("Delete")
			);
			d.get_primary_btn().addClass("btn-danger");
		});
	}
});

erpnext.company.set_chart_of_accounts_options = function(doc) {
	var selected_value = doc.chart_of_accounts;
	if(doc.country) {
		return frappe.call({
			method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.get_charts_for_country",
			args: {
				"country": doc.country,
				"with_standard": true
			},
			callback: function(r) {
				if(!r.exc) {
					set_field_options("chart_of_accounts", [""].concat(r.message).join("\n"));
					if(in_list(r.message, selected_value))
						cur_frm.set_value("chart_of_accounts", selected_value);
				}
			}
		})
	}
}

cur_frm.cscript.change_abbr = function() {
	var dialog = new frappe.ui.Dialog({
		title: "Replace Abbr",
		fields: [
			{"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
				"reqd": 1 },
			{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
		]
	});

	dialog.fields_dict.update.$input.click(function() {
		var args = dialog.get_values();
		if(!args) return;
		frappe.show_alert(__("Update in progress. It might take a while."));
		return frappe.call({
			method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
			args: {
				"company": cur_frm.doc.name,
				"old": cur_frm.doc.abbr,
				"new": args.new_abbr
			},
			callback: function(r) {
				if(r.exc) {
					frappe.msgprint(__("There were errors."));
					return;
				} else {
					cur_frm.set_value("abbr", args.new_abbr);
				}
				dialog.hide();
				cur_frm.refresh();
			},
			btn: this
		})
	});
	dialog.show();
}

erpnext.company.setup_queries = function(frm) {
	$.each([
		["default_bank_account", {"account_type": "Bank"}],
		["default_cash_account", {"account_type": "Cash"}],
		["default_receivable_account", {"account_type": "Receivable"}],
		["default_payable_account", {"account_type": "Payable"}],
		["default_expense_account", {"root_type": "Expense"}],
		["default_income_account", {"root_type": "Income"}],
		["default_payroll_payable_account", {"root_type": "Liability"}],
		["round_off_account", {"root_type": "Expense"}],
		["write_off_account", {"root_type": "Expense"}],
		["exchange_gain_loss_account", {"root_type": "Expense"}],
		["accumulated_depreciation_account",
			{"root_type": "Asset", "account_type": "Accumulated Depreciation"}],
		["depreciation_expense_account", {"root_type": "Expense", "account_type": "Depreciation"}],
		["disposal_account", {"report_type": "Profit and Loss"}],
		["default_inventory_account", {"account_type": "Stock"}],
		["cost_center", {}],
		["round_off_cost_center", {}],
		["depreciation_cost_center", {}],
		["default_employee_advance_account", {"root_type": "Asset"}],
	], function(i, v) {
		erpnext.company.set_custom_query(frm, v);
	});

	if (frm.doc.enable_perpetual_inventory) {
		$.each([
			["stock_adjustment_account",
				{"root_type": "Expense", "account_type": "Stock Adjustment"}],
			["expenses_included_in_valuation",
				{"root_type": "Expense", "account_type": "Expenses Included in Valuation"}],
			["stock_received_but_not_billed",
				{"root_type": "Liability", "account_type": "Stock Received But Not Billed"}]
		], function(i, v) {
			erpnext.company.set_custom_query(frm, v);
		});
	}
}

erpnext.company.set_custom_query = function(frm, v) {
	var filters = {
		"company": frm.doc.name,
		"is_group": 0
	};

	for (var key in v[1]) {
		filters[key] = v[1][key];
	}

	frm.set_query(v[0], function() {
		return {
			filters: filters
		}
	});
}
<commit_msg>[minor] company.js buttons should be primary!<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.provide("erpnext.company");

frappe.ui.form.on("Company", {
	setup: function(frm) {
		erpnext.company.setup_queries(frm);
	},

	company_name: function(frm) {
		if(frm.doc.__islocal) {
			let parts = frm.doc.company_name.split();
			let abbr = $.map(parts, function (p) {
				return p? p.substr(0, 1) : null;
			}).join("");
			frm.set_value("abbr", abbr);
		}
	},

	refresh: function(frm) {
		if(frm.doc.abbr && !frm.doc.__islocal) {
			frm.set_df_property("abbr", "read_only", 1);
		}

		frm.toggle_display('address_html', !frm.doc.__islocal);
		if(!frm.doc.__islocal) {
			frappe.contacts.render_address_and_contact(frm);

			frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Company'}

			frm.toggle_enable("default_currency", (frm.doc.__onload &&
				!frm.doc.__onload.transactions_exist));

			frm.add_custom_button(__('Cost Centers'), function() {
				frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name})
			}, __("View"));

			frm.add_custom_button(__('Chart of Accounts'), function() {
				frappe.set_route('Tree', 'Account', {'company': frm.doc.name})
			}, __("View"));

			frm.add_custom_button(__('Sales Tax Template'), function() {
				frappe.set_route('List', 'Sales Taxes and Charges Template', {'company': frm.doc.name});
			}, __("View"));

			frm.add_custom_button(__('Purchase Tax Template'), function() {
				frappe.set_route('List', 'Purchase Taxes and Charges Template', {'company': frm.doc.name});
			}, __("View"));

			frm.add_custom_button(__('Default Tax Template'), function() {
				frm.trigger("make_default_tax_template");
			}, __("Make"));
		}

		erpnext.company.set_chart_of_accounts_options(frm.doc);

	},

	make_default_tax_template: function(frm) {
		frm.call({
			method: "create_default_tax_template",
			doc: frm.doc,
			freeze: true,
			callback: function() {
				frappe.msgprint(__("Default tax templates for sales and purchase are created."));
			}
		})
	},

	onload_post_render: function(frm) {
		if(frm.get_field("delete_company_transactions").$input)
			frm.get_field("delete_company_transactions").$input.addClass("btn-danger");
	},

	country: function(frm) {
		erpnext.company.set_chart_of_accounts_options(frm.doc);
	},

	delete_company_transactions: function(frm) {
		frappe.verify_password(function() {
			var d = frappe.prompt({
				fieldtype:"Data",
				fieldname: "company_name",
				label: __("Please re-type company name to confirm"),
				reqd: 1,
				description: __("Please make sure you really want to delete all the transactions for this company. Your master data will remain as it is. This action cannot be undone.")
			},
			function(data) {
				if(data.company_name !== frm.doc.name) {
					frappe.msgprint("Company name not same");
					return;
				}
				frappe.call({
					method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
					args: {
						company_name: data.company_name
					},
					freeze: true,
					callback: function(r, rt) {
						if(!r.exc)
							frappe.msgprint(__("Successfully deleted all transactions related to this company!"));
					},
					onerror: function() {
						frappe.msgprint(__("Wrong Password"));
					}
				});
			},
			__("Delete all the Transactions for this Company"), __("Delete")
			);
			d.get_primary_btn().addClass("btn-danger");
		});
	}
});

erpnext.company.set_chart_of_accounts_options = function(doc) {
	var selected_value = doc.chart_of_accounts;
	if(doc.country) {
		return frappe.call({
			method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.get_charts_for_country",
			args: {
				"country": doc.country,
				"with_standard": true
			},
			callback: function(r) {
				if(!r.exc) {
					set_field_options("chart_of_accounts", [""].concat(r.message).join("\n"));
					if(in_list(r.message, selected_value))
						cur_frm.set_value("chart_of_accounts", selected_value);
				}
			}
		})
	}
}

cur_frm.cscript.change_abbr = function() {
	var dialog = new frappe.ui.Dialog({
		title: "Replace Abbr",
		fields: [
			{"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
				"reqd": 1 },
			{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
		]
	});

	dialog.fields_dict.update.$input.click(function() {
		var args = dialog.get_values();
		if(!args) return;
		frappe.show_alert(__("Update in progress. It might take a while."));
		return frappe.call({
			method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
			args: {
				"company": cur_frm.doc.name,
				"old": cur_frm.doc.abbr,
				"new": args.new_abbr
			},
			callback: function(r) {
				if(r.exc) {
					frappe.msgprint(__("There were errors."));
					return;
				} else {
					cur_frm.set_value("abbr", args.new_abbr);
				}
				dialog.hide();
				cur_frm.refresh();
			},
			btn: this
		})
	});
	dialog.show();
}

erpnext.company.setup_queries = function(frm) {
	$.each([
		["default_bank_account", {"account_type": "Bank"}],
		["default_cash_account", {"account_type": "Cash"}],
		["default_receivable_account", {"account_type": "Receivable"}],
		["default_payable_account", {"account_type": "Payable"}],
		["default_expense_account", {"root_type": "Expense"}],
		["default_income_account", {"root_type": "Income"}],
		["default_payroll_payable_account", {"root_type": "Liability"}],
		["round_off_account", {"root_type": "Expense"}],
		["write_off_account", {"root_type": "Expense"}],
		["exchange_gain_loss_account", {"root_type": "Expense"}],
		["accumulated_depreciation_account",
			{"root_type": "Asset", "account_type": "Accumulated Depreciation"}],
		["depreciation_expense_account", {"root_type": "Expense", "account_type": "Depreciation"}],
		["disposal_account", {"report_type": "Profit and Loss"}],
		["default_inventory_account", {"account_type": "Stock"}],
		["cost_center", {}],
		["round_off_cost_center", {}],
		["depreciation_cost_center", {}],
		["default_employee_advance_account", {"root_type": "Asset"}],
	], function(i, v) {
		erpnext.company.set_custom_query(frm, v);
	});

	if (frm.doc.enable_perpetual_inventory) {
		$.each([
			["stock_adjustment_account",
				{"root_type": "Expense", "account_type": "Stock Adjustment"}],
			["expenses_included_in_valuation",
				{"root_type": "Expense", "account_type": "Expenses Included in Valuation"}],
			["stock_received_but_not_billed",
				{"root_type": "Liability", "account_type": "Stock Received But Not Billed"}]
		], function(i, v) {
			erpnext.company.set_custom_query(frm, v);
		});
	}
}

erpnext.company.set_custom_query = function(frm, v) {
	var filters = {
		"company": frm.doc.name,
		"is_group": 0
	};

	for (var key in v[1]) {
		filters[key] = v[1][key];
	}

	frm.set_query(v[0], function() {
		return {
			filters: filters
		}
	});
}
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert'),
    path = require('path'),
    HTML = require('../../lib/common/html'),
    escapeString = require('../../lib/serializer').escapeString,
    parse5 = require('../../lib'),
    testUtils = require('../test_utils');

function getFullLocationTestName(test) {
    return ['Location info (Parser) - ', test.name].join('');
}

function walkTree(document, treeAdapter, handler) {
    for (var stack = treeAdapter.getChildNodes(document).slice(); stack.length;) {
        var node = stack.shift(),
            children = treeAdapter.getChildNodes(node);

        handler(node);

        if (children && children.length)
            stack = children.concat(stack);
    }
}

function assertLocation(loc, expected, html, lines) {
    //Offsets
    var actual = html.substring(loc.startOffset, loc.endOffset);

    expected = testUtils.removeNewLines(expected);
    actual = testUtils.removeNewLines(actual);

    assert.strictEqual(expected, actual, testUtils.getStringDiffMsg(actual, expected));

    //Line/col
    actual = testUtils.getSubstringByLineCol(lines, loc.line, loc.col);
    actual = testUtils.removeNewLines(actual);

    assert.strictEqual(actual.indexOf(expected), 0, testUtils.getStringDiffMsg(actual, expected));
}

//NOTE: Based on the idea that the serialized fragment starts with the startTag
function assertStartTagLocation(node, serializedNode, html, lines) {
    var length = node.__location.startTag.endOffset - node.__location.startTag.startOffset,
        expected = serializedNode.substring(0, length);

    assertLocation(node.__location.startTag, expected, html, lines);
}

//NOTE: Based on the idea that the serialized fragment ends with the endTag
function assertEndTagLocation(node, serializedNode, html, lines) {
    var length = node.__location.endTag.endOffset - node.__location.endTag.startOffset,
        expected = serializedNode.slice(-length);

    assertLocation(node.__location.endTag, expected, html, lines);
}

function assertAttrsLocation(node, serializedNode, html, lines) {
    node.__location.attrs.forEach(function (attr) {
        var expected = serializedNode.slice(attr.startOffset, attr.endOffset);

        assertLocation(attr, expected, html, lines);
    });
}

function assertNodeLocation(node, serializedNode, html, lines) {
    var expected = testUtils.removeNewLines(serializedNode);

    assertLocation(node.__location, expected, html, lines);
}

testUtils.generateTestsForEachTreeAdapter(module.exports, function (_test, treeAdapter) {
    testUtils
        .loadSerializationTestData(path.join(__dirname, '../data/serialization'))
        .forEach(function (test) {
            //NOTE: How it works: we parse document with the location info.
            //Then for each node in the tree we run serializer and compare results with the substring
            //obtained via location info from the expected serialization results.
            _test[getFullLocationTestName(test)] = function () {
                var serializerOpts = {
                        treeAdapter: treeAdapter
                    },
                    html = escapeString(test.expected),
                    lines = html.split(/\r?\n/g),
                    parserOpts = {
                        treeAdapter: treeAdapter,
                        locationInfo: true
                    };

                // NOTE: because of performance use bigger chunks here
                var parsingResult = testUtils.parseChunked(html, parserOpts, 100, 400),
                    document = parsingResult.document;

                walkTree(document, treeAdapter, function (node) {
                    if (node.__location) {
                        var fragment = treeAdapter.createDocumentFragment();

                        treeAdapter.appendChild(fragment, node);

                        var serializedNode = parse5.serialize(fragment, serializerOpts);

                        assertNodeLocation(node, serializedNode, html, lines);

                        if (node.__location.startTag)
                            assertStartTagLocation(node, serializedNode, html, lines);

                        if (node.__location.endTag)
                            assertEndTagLocation(node, serializedNode, html, lines);

                        if (node.__location.attrs)
                            assertAttrsLocation(node, serializedNode, html, lines);
                    }
                });
            };
        });

    exports['Regression - location info for the implicitly generated ,  and  (GH-44)'] = function () {
        var html = '

',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var document = testUtils.parseChunked(html, opts).document;

        //NOTE: location info for all implicitly generated elements should be null
        walkTree(document, treeAdapter, function (node) {
            if (treeAdapter.getTagName(node) !== HTML.TAG_NAMES.DIV)
                assert.strictEqual(node.__location, null);
        });
    };

    exports['Regression - location info for the implicitly generated ,  and  (GH-44)'] = function () {
        var html = '
1
3',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var fragment = parse5.parseFragment(html, opts),
            firstPLocation = fragment.childNodes[0].__location;

        assert.strictEqual(html.substring(firstPLocation.startOffset, firstPLocation.endOffset), '
1');
    };

    exports['Regression - Incorrect LocationInfo.endOffset for implicitly closed
 element (GH-109)'] = function () {
        var html = 'foo',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var fragment = parse5.parseFragment(html, opts);

        assert.ok(fragment.childNodes[0].__location);
    };

    exports['Regression - location info mixin error when parsing <template> elements (GH-90)'] = function () {
        var html = '<template>hello</template>',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        assert.doesNotThrow(function () {
            parse5.parseFragment(html, opts);
        });
    };

    exports['Regression - location info not attached for empty attributes (GH-96)'] = function () {
        var html = '

',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var fragment = parse5.parseFragment(html, opts);

        assert.ok(fragment.childNodes[0].__location.attrs['test-attr']);
    };

    exports['Regression - location line incorrect when a character is unconsumed (GH-151)'] = function () {
        var html = ['',
                '',
                ''].join('\n'),
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var doc = parse5.parse(html, opts),
            foundScript = false;

        walkTree(doc, treeAdapter, function (node) {
            if (node.name === 'script') {
                foundScript = true;
                assert.equal(node.__location.endTag.line, 5);
            }
        });

        assert.ok(foundScript);
    };
});
<commit_msg>Fix test name in previous commit<commit_after>'use strict';

var assert = require('assert'),
    path = require('path'),
    HTML = require('../../lib/common/html'),
    escapeString = require('../../lib/serializer').escapeString,
    parse5 = require('../../lib'),
    testUtils = require('../test_utils');

function getFullLocationTestName(test) {
    return ['Location info (Parser) - ', test.name].join('');
}

function walkTree(document, treeAdapter, handler) {
    for (var stack = treeAdapter.getChildNodes(document).slice(); stack.length;) {
        var node = stack.shift(),
            children = treeAdapter.getChildNodes(node);

        handler(node);

        if (children && children.length)
            stack = children.concat(stack);
    }
}

function assertLocation(loc, expected, html, lines) {
    //Offsets
    var actual = html.substring(loc.startOffset, loc.endOffset);

    expected = testUtils.removeNewLines(expected);
    actual = testUtils.removeNewLines(actual);

    assert.strictEqual(expected, actual, testUtils.getStringDiffMsg(actual, expected));

    //Line/col
    actual = testUtils.getSubstringByLineCol(lines, loc.line, loc.col);
    actual = testUtils.removeNewLines(actual);

    assert.strictEqual(actual.indexOf(expected), 0, testUtils.getStringDiffMsg(actual, expected));
}

//NOTE: Based on the idea that the serialized fragment starts with the startTag
function assertStartTagLocation(node, serializedNode, html, lines) {
    var length = node.__location.startTag.endOffset - node.__location.startTag.startOffset,
        expected = serializedNode.substring(0, length);

    assertLocation(node.__location.startTag, expected, html, lines);
}

//NOTE: Based on the idea that the serialized fragment ends with the endTag
function assertEndTagLocation(node, serializedNode, html, lines) {
    var length = node.__location.endTag.endOffset - node.__location.endTag.startOffset,
        expected = serializedNode.slice(-length);

    assertLocation(node.__location.endTag, expected, html, lines);
}

function assertAttrsLocation(node, serializedNode, html, lines) {
    node.__location.attrs.forEach(function (attr) {
        var expected = serializedNode.slice(attr.startOffset, attr.endOffset);

        assertLocation(attr, expected, html, lines);
    });
}

function assertNodeLocation(node, serializedNode, html, lines) {
    var expected = testUtils.removeNewLines(serializedNode);

    assertLocation(node.__location, expected, html, lines);
}

testUtils.generateTestsForEachTreeAdapter(module.exports, function (_test, treeAdapter) {
    testUtils
        .loadSerializationTestData(path.join(__dirname, '../data/serialization'))
        .forEach(function (test) {
            //NOTE: How it works: we parse document with the location info.
            //Then for each node in the tree we run serializer and compare results with the substring
            //obtained via location info from the expected serialization results.
            _test[getFullLocationTestName(test)] = function () {
                var serializerOpts = {
                        treeAdapter: treeAdapter
                    },
                    html = escapeString(test.expected),
                    lines = html.split(/\r?\n/g),
                    parserOpts = {
                        treeAdapter: treeAdapter,
                        locationInfo: true
                    };

                // NOTE: because of performance use bigger chunks here
                var parsingResult = testUtils.parseChunked(html, parserOpts, 100, 400),
                    document = parsingResult.document;

                walkTree(document, treeAdapter, function (node) {
                    if (node.__location) {
                        var fragment = treeAdapter.createDocumentFragment();

                        treeAdapter.appendChild(fragment, node);

                        var serializedNode = parse5.serialize(fragment, serializerOpts);

                        assertNodeLocation(node, serializedNode, html, lines);

                        if (node.__location.startTag)
                            assertStartTagLocation(node, serializedNode, html, lines);

                        if (node.__location.endTag)
                            assertEndTagLocation(node, serializedNode, html, lines);

                        if (node.__location.attrs)
                            assertAttrsLocation(node, serializedNode, html, lines);
                    }
                });
            };
        });

    exports['Regression - location info for the implicitly generated ,  and  (GH-44)'] = function () {
        var html = '

',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var document = testUtils.parseChunked(html, opts).document;

        //NOTE: location info for all implicitly generated elements should be null
        walkTree(document, treeAdapter, function (node) {
            if (treeAdapter.getTagName(node) !== HTML.TAG_NAMES.DIV)
                assert.strictEqual(node.__location, null);
        });
    };

    exports['Regression - Incorrect LocationInfo.endOffset for implicitly closed
 element (GH-109)'] = function () {
        var html = '
1
3',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var fragment = parse5.parseFragment(html, opts),
            firstPLocation = fragment.childNodes[0].__location;

        assert.strictEqual(html.substring(firstPLocation.startOffset, firstPLocation.endOffset), '
1');
    };

    exports['Regression - Location info not exposed with parseFragment (GH-82)'] = function () {
        var html = 'foo',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var fragment = parse5.parseFragment(html, opts);

        assert.ok(fragment.childNodes[0].__location);
    };

    exports['Regression - location info mixin error when parsing <template> elements (GH-90)'] = function () {
        var html = '<template>hello</template>',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        assert.doesNotThrow(function () {
            parse5.parseFragment(html, opts);
        });
    };

    exports['Regression - location info not attached for empty attributes (GH-96)'] = function () {
        var html = '

',
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var fragment = parse5.parseFragment(html, opts);

        assert.ok(fragment.childNodes[0].__location.attrs['test-attr']);
    };

    exports['Regression - location line incorrect when a character is unconsumed (GH-151)'] = function () {
        var html = ['',
                '',
                ''].join('\n'),
            opts = {
                treeAdapter: treeAdapter,
                locationInfo: true
            };

        var doc = parse5.parse(html, opts),
            foundScript = false;

        walkTree(doc, treeAdapter, function (node) {
            if (node.name === 'script') {
                foundScript = true;
                assert.equal(node.__location.endTag.line, 5);
            }
        });

        assert.ok(foundScript);
    };
});
<|endoftext|>


<commit_before>import { push, LOCATION_CHANGE } from 'react-router-redux';

function hasAccess() {
  return false;
}

export default function adminAccess(action$) {
  return action$.ofType(LOCATION_CHANGE)
    .map(action => action.payload.pathname)
    .filter(pathname => pathname === '/admin')
    .map(hasAccess)
    .filter(access => !access)
    .delay(2000)
    .map(() => push('/'));
}
<commit_msg>docs(example comment): Replace dummy code with comment to prevent confusion<commit_after>import { push, LOCATION_CHANGE } from 'react-router-redux';

export default function adminAccess(action$) {
  return action$.ofType(LOCATION_CHANGE)
    .map(action => action.payload.pathname)
    .filter(pathname => pathname === '/admin')
    // If you wanted to do an actual access check you
    // could do so here then filter by failed checks.
    .delay(2000)
    .map(() => push('/'));
}
<|endoftext|>


<commit_before>'use strict';

define(['frontend/providers/notify'], function(notify) {
});
<commit_msg>Added notifier spec.<commit_after>'use strict';

define(['angular-mocks', 'frontend/providers/notify'], function(mocks) {
  describe('Notify provider', function() {

    var notify, toaster, ngProgress;

    beforeEach(mocks.module("DarkWallet.providers"));
    beforeEach(function() {
      mocks.module(function($provide) {
        // Override services
        $provide.value('toaster', {});
        $provide.value('ngProgress', {});
      });
    });
    beforeEach(mocks.inject(['notify', 'toaster', 'ngProgress', function(_notify_, _toaster_, _ngProgress_) {
      notify = _notify_;
      toaster = _toaster_;
      ngProgress = _ngProgress_;

      toaster.pop = function() {};
      spyOn(toaster, 'pop');

    }]));

    it('notifies a note', function() {
      notify.note('hello', 'world');
      expect(toaster.pop).toHaveBeenCalledWith('note', 'hello', 'world');
    });

    it('notifies an error', function() {
      notify.error('hello', 'world');
      expect(toaster.pop).toHaveBeenCalledWith('error', 'hello', 'world');
    });

    it('notifies a warning', function() {
      notify.warning('hello', 'world');
      expect(toaster.pop).toHaveBeenCalledWith('warning', 'hello', 'world');
    });

    it('notifies a success', function() {
      notify.success('hello', 'world');
      expect(toaster.pop).toHaveBeenCalledWith('success', 'hello', 'world');
    });

    it('wrapps ngProgress', function() {
      expect(notify.progress).toBe(ngProgress);
    })
  });
});<|endoftext|>


<commit_before>'use strict';

import chai, { expect } from 'chai';
import sinon from 'sinon';
import { default as sinonChai } from 'sinon-chai';
import InstallController from 'browser/pages/install/controller';
import { ProgressState } from 'browser/pages/install/controller';
import InstallerDataService from 'browser/services/data';
import VirtualBoxInstall from 'browser/model/virtualbox';
import JdkInstall from 'browser/model/jdk-install';
import InstallableItem from 'browser/model/installable-item';
import Logger from 'browser/services/logger';
import ElectronMock from '../../../mock/electron';
import { JSDOM } from 'jsdom';
import fs from 'fs';
chai.use(sinonChai);

describe('Install controller', function() {

  let installerDataSvc, sandbox;
  let vbox;
  let logStub, fsStub, infoStub, errorStub;
  let timeoutStub = sinon.stub();
  let window = new JSDOM('<html>').window;

  before(function() {
    logStub = sinon.stub(Logger, 'initialize');
    infoStub = sinon.stub(Logger, 'info');
    errorStub = sinon.stub(Logger, 'error');
    fsStub = sinon.stub(fs, 'mkdirSync');
  });

  after(function() {
    logStub.restore();
    fsStub.restore();
    infoStub.restore();
    errorStub.restore();
  });

  beforeEach(function() {
    sandbox = sinon.sandbox.create();
    sandbox.stub(InstallerDataService.prototype, 'copyUninstaller').returns();
    installerDataSvc = new InstallerDataService();
    installerDataSvc.setup('installRoot');
    vbox = new VirtualBoxInstall(installerDataSvc, 'virtualbox',
      'http://download.virtualbox.org/virtualbox/${version}/VirtualBox-${version}-${revision}-Win.exe', 'virtualbox.exe', 'sha', '5.0.8', '103449');

    installerDataSvc.addItemToInstall(VirtualBoxInstall.KEY, vbox);
  });

  afterEach(function() {
    sandbox.restore();
  });

  describe('constrution', function() {
    it('should verify existing files', function() {
      let stub = sandbox.stub(installerDataSvc, 'verifyFiles').returns();
      new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(stub).calledOnce;
    });

    it('should register an event handler for 3 different events', function() {
      sandbox.stub(installerDataSvc, 'verifyFiles').returns();
      let tron = {
        ipcRenderer: {
          setMaxListeners: function() {},
          on: function() {}
        }
      };

      let spy = sandbox.spy(tron.ipcRenderer, 'on');
      new InstallController({}, {}, installerDataSvc, tron, window);

      expect(spy).calledThrice;
      expect(spy).calledWith('checkComplete');
      expect(spy).calledWith('downloadingComplete');
      expect(spy).calledWith('installComplete');
    });
  });

  describe('verifyFiles', function() {
    let verifyStub;

    beforeEach(function() {
      verifyStub = sandbox.stub(installerDataSvc, 'verifyExistingFiles').returns();
    });

    it('should select component for file verification if some of its files are downloaded', function() {
      vbox.files.virtualbox.downloaded = true;
      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWith(ctrl.itemProgress, 'virtualbox');
    });

    it('should skip a component if none of its files are downloaded', function() {
      vbox.files.virtualbox.downloaded = false;
      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWithExactly(ctrl.itemProgress);
    });

    it('should skip a component if it is bundled', function() {
      vbox.files.virtualbox.downloaded = true;
      vbox.downloadedFile = vbox.bundledFile;
      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWithExactly(ctrl.itemProgress);
    });

    it('should work for multiple components', function() {
      vbox.files.virtualbox.downloaded = true;
      let jdk = new JdkInstall(installerDataSvc, 'jdk8', 'downloadUrl', 'fileName', 'sha256sum');
      installerDataSvc.addItemToInstall('jdk', jdk);
      jdk.files.jdk.downloaded = true;

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWith(ctrl.itemProgress, 'virtualbox', 'jdk');
    });
  });

  describe('downloadFiles', function() {
    let dlStub, progressStub;

    beforeEach(function() {
      sandbox.stub(installerDataSvc, 'verifyExistingFiles').returns();
      dlStub = sandbox.stub(installerDataSvc, 'download').returns();
      progressStub = sandbox.stub(ProgressState.prototype, 'setTotalAmount').returns();
    });

    it('should process components that require download', function() {
      let jdk = new JdkInstall(installerDataSvc, 'jdk8', 'downloadUrl', 'fileName', 'sha256sum');
        installerDataSvc.addItemToInstall('jdk', jdk);
      vbox.downloaded = false;
      jdk.downloaded = true;

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);
      installerDataSvc.downloadFiles(ctrl.itemProgress, window.navigator.userAgent);

      expect(dlStub).calledOnce;
      expect(dlStub).calledWithExactly(ctrl.itemProgress, 1, window.navigator.userAgent, 'virtualbox');
    });

    it('should set the total amount to the sum of file sizes', function() {
      vbox.useDownload = true;
      vbox.files.foo = {
        dmUrl: 'downloadUrl',
        fileName: 'foo.bar',
        sha256sum: 'sum',
        size: 123
      };

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);
      installerDataSvc.downloadFiles(ctrl.itemProgress, ctrl.$window.navigator.userAgent);

      expect(progressStub).calledOnce;
      expect(progressStub).calledWith(vbox.files.virtualbox.size + vbox.files.foo.size);
    });

    it('should set total download count to number of pending files', function() {
      let jdk = new JdkInstall(installerDataSvc, 'jdk8', 'downloadUrl', 'fileName', 'sha256sum');
      installerDataSvc.addItemToInstall('jdk', jdk);
      jdk.useDownload = true;
      vbox.useDownload = true;
      vbox.files.foo = {
        dmUrl: 'downloadUrl',
        fileName: 'foo.bar',
        sha256sum: 'sum',
        size: 123
      };

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);
      installerDataSvc.downloadFiles(ctrl.itemProgress, ctrl.$window.navigator.userAgent);

      expect(dlStub).calledOnce;
      expect(dlStub).calledWithExactly(ctrl.itemProgress, 3, ctrl.$window.navigator.userAgent, 'virtualbox', 'jdk');
    });
  });

  describe('triggerInstall', function() {
    let vboxStub, doneStub;

    beforeEach(function() {
      sandbox.stub(vbox, 'isDownloadRequired').returns(false);
      vboxStub = sandbox.stub(vbox, 'install').yields();
      doneStub = sandbox.stub(installerDataSvc, 'installDone').returns();
    });

    it.skip('logs error in case of install failed', function() {
      vbox.install.restore();
      sandbox.stub(vbox, 'install').callsArgWith(2, 'Error');
      new InstallController({}, timeoutStub, installerDataSvc, new ElectronMock());
      expect(errorStub).calledTwice;
    });

    it.skip('should call the installables install method', function() {
      sandbox.stub(installerDataSvc, 'startInstall').returns();

      new InstallController({}, timeoutStub, installerDataSvc, new ElectronMock());
      expect(vboxStub).calledOnce;
    });

    it.skip('should call data services installDone when install finishes', function() {
      sandbox.stub(installerDataSvc, 'startInstall').returns();

      new InstallController({}, timeoutStub, installerDataSvc, new ElectronMock());

      expect(doneStub).calledOnce;
      expect(doneStub).calledWith(sinon.match.any, 'virtualbox');
    });
  });

  describe('ProgressState', function() {
    it('should set default min/max values when passed to constructor', function() {
      let progress = new ProgressState('key', 'prodName', 'prodVersion', 'productDesc', {}, sinon.stub(), 100, 1000);
      expect(progress.min).equals(100);
      expect(progress.max).equals(1000);
    });
    describe('setTotalDownloadSize', function() {
      it('should set totalSize property value', function() {
        let progress = new ProgressState();
        progress.setTotalAmount(1000);
        expect(progress.totalAmount).to.be.equal(1000);
      });
    });
    describe('setCurrent', function() {
      describe('should update', function() {
        let progress;
        beforeEach(function() {
          progress = new ProgressState();
          progress.$timeout = sinon.stub();
          progress.$scope = {$apply:sinon.stub()};
          progress.setStatus('Downloading');
          progress.setTotalAmount(1000);
          progress.setCurrent(100);
        });
        it('current progress amount value', function() {
          expect(progress.currentAmount).equals(100);
        });
        it('current prcentage', function() {
          expect(progress.current).equals(10);
        });
        it('lable value', function() {
          expect(progress.label).to.have.string(
            progress.sizeInKB(progress.currentAmount) + ' / ' + progress.sizeInKB(progress.totalAmount) + ' (' + progress.current + '%)'
          );
        });
        it('ETA to second', function() {
          sinon.stub(progress, 'calculateTime').returns(1000);
          progress.setCurrent(101);
          expect(progress.label).to.have.string('sec');
        });
        it('ETA to seconds', function() {
          sinon.stub(progress, 'calculateTime').returns(45000);
          progress.setCurrent(102);
          expect(progress.label).to.have.string('secs');
        });
        it('ETA to minute', function() {
          sinon.stub(progress, 'calculateTime').returns(65000);
          progress.setCurrent(103);
          expect(progress.label).to.have.string('min');
        });
        it('ETA to minutes', function() {
          sinon.stub(progress, 'calculateTime').returns(125000);
          progress.setCurrent(104);
          expect(progress.label).to.have.string('mins');
        });
        it('ETA to hour', function() {
          sinon.stub(progress, 'calculateTime').returns(3600000);
          progress.setCurrent(105);
          expect(progress.label).to.have.string('hr');
        });
        it('ETA to hours', function() {
          sinon.stub(progress, 'calculateTime').returns(7200000);
          progress.setCurrent(106);
          expect(progress.label).to.have.string('hrs');
        });
        it('ETA to day', function() {
          sinon.stub(progress, 'calculateTime').returns(3600000*24);
          progress.setCurrent(105);
          expect(progress.label).to.have.string('day');
        });
        it('ETA to days', function() {
          sinon.stub(progress, 'calculateTime').returns(7200000*24);
          progress.setCurrent(106);
          expect(progress.label).to.have.string('days');
        });
        it('ETA to year', function() {
          sinon.stub(progress, 'calculateTime').returns(3600000*24*366);
          progress.setCurrent(105);
          expect(progress.label).to.have.string('year');
        });
        it('ETA to years', function() {
          sinon.stub(progress, 'calculateTime').returns(7200000*24*366);
          progress.setCurrent(106);
          expect(progress.label).to.have.string('years');
        });

      });
    });
    describe('setStatus', function() {
      let progress;
      beforeEach(function() {
        progress = new ProgressState();
        progress.$timeout = sinon.stub();
        progress.$scope = {$apply:sinon.stub()};
      });
      it('does nothing if status is the same', function() {
        progress.current = 1;
        progress.setStatus('');
        expect(progress.current).equals(1);
      });
      it.skip('sets prcentage to 100 and clear lable if status is not "Downloading"', function() {
        progress.setStatus('Verifying something');
        expect(progress.$scope.$apply).have.been.calledOnce;
        expect(progress.label).equals('');
        expect(progress.current).equals(100);
      });
      it.skip('resets downloading stats if status is "Downloading"', function() {
        progress.setStatus('Downloading');
        expect(progress.$scope.$apply).have.been.calledOnce;
        expect(progress.current).equals(0);
        expect(progress.label).equals(0 + '%');
        expect(progress.currentAmount).equals(0);
        expect(progress.totalSize).equals(0);
      });
    });
    describe('setComplete', function() {
      let progress;
      before(function() {
        progress = new ProgressState();
        progress.$timeout = sinon.stub();
        progress.$scope = {$apply:sinon.stub()};
        progress.setTotalAmount(1000);
        progress.setCurrent(100);
        progress.setComplete();
      });
      it('sets status to "Complete"', function() {
        expect(progress.status).equals('Complete');
      });
    });
    describe('calculateTime', function() {
      let progress;
      beforeEach(function() {
        progress = new ProgressState();
        progress.lastTime = 100000;
        progress.totalAmount = 9000000;
        progress.currentAmount = 400000;
        sandbox.stub(Date.prototype, 'getTime').returns(101000);
      });

      it('returns time estimate based on average speed', function() {
        expect(progress.calculateTime()).to.equal((9000000 - 400000) / 400);
      });

      it('uses exponential moving average speed', function() {
        progress.averageSpeed = 800;

        //average speed moves with a smoothing factor
        let result = progress.calculateTime();
        expect(progress.averageSpeed).to.equal(0.15 * 400 + 0.85 * 800);
        expect(result).to.equal((9000000 - 400000) / (0.15 * 400 + 0.85 * 800));
      });
    });

    describe('resetTime', function() {
      it('resets speed and time calculation', function() {
        let progress = new ProgressState();
        progress.lastTime = 100000;
        progress.lastSpeed = 1000;
        progress.averageSpeed = 100;
        progress.totalAmount = 9000000;
        progress.currentAmount = 400000;

        progress.resetTime();

        expect(progress.lastSpeed).to.equal(0);
        expect(progress.lastAmount).to.equal(progress.currentAmount);
        expect(progress.averageSpeed).to.equal(0);
      });
    });

    describe('exit', function() {
      it('exit closes active window', function() {
        let electron = new ElectronMock();
        sandbox.stub(installerDataSvc, 'verifyFiles').returns();
        sandbox.stub(electron.remote.currentWindow);
        let installController = new InstallController({}, {}, installerDataSvc, electron, window);
        installController.exit();
        expect(electron.remote.currentWindow.close).calledOnce;
      });
    });
  });

  it.skip('downloadAgain closes dialog with error and start download for failed installers', function() {
    sandbox.stub(InstallableItem.prototype, 'downloadInstaller');
    sandbox.stub(InstallableItem.prototype, 'restartDownload').returns();

    let scopeStub = {
      $apply: function(callback) {
        callback && callback();
      }
    };

    let timeoutStub = function(callback) {
      callback && callback();
    };

    let installCtrl = new InstallController(scopeStub, timeoutStub, installerDataSvc, new ElectronMock());
    sandbox.spy(installCtrl, 'closeDownloadAgainDialog');
    installCtrl.downloadAgain();
    expect(InstallableItem.prototype.restartDownload).calledOnce;
    expect(installCtrl.closeDownloadAgainDialog).calledOnce;
  });
});
<commit_msg>Remove skipped unit tests for install controller<commit_after>'use strict';

import chai, { expect } from 'chai';
import sinon from 'sinon';
import { default as sinonChai } from 'sinon-chai';
import InstallController from 'browser/pages/install/controller';
import { ProgressState } from 'browser/pages/install/controller';
import InstallerDataService from 'browser/services/data';
import VirtualBoxInstall from 'browser/model/virtualbox';
import JdkInstall from 'browser/model/jdk-install';
import InstallableItem from 'browser/model/installable-item';
import Logger from 'browser/services/logger';
import ElectronMock from '../../../mock/electron';
import { JSDOM } from 'jsdom';
import fs from 'fs';
chai.use(sinonChai);

describe('Install controller', function() {

  let installerDataSvc, sandbox;
  let vbox;
  let logStub, fsStub, infoStub, errorStub;
  let timeoutStub = sinon.stub();
  let window = new JSDOM('<html>').window;

  before(function() {
    logStub = sinon.stub(Logger, 'initialize');
    infoStub = sinon.stub(Logger, 'info');
    errorStub = sinon.stub(Logger, 'error');
    fsStub = sinon.stub(fs, 'mkdirSync');
  });

  after(function() {
    logStub.restore();
    fsStub.restore();
    infoStub.restore();
    errorStub.restore();
  });

  beforeEach(function() {
    sandbox = sinon.sandbox.create();
    sandbox.stub(InstallerDataService.prototype, 'copyUninstaller').returns();
    installerDataSvc = new InstallerDataService();
    installerDataSvc.setup('installRoot');
    vbox = new VirtualBoxInstall(installerDataSvc, 'virtualbox',
      'http://download.virtualbox.org/virtualbox/${version}/VirtualBox-${version}-${revision}-Win.exe', 'virtualbox.exe', 'sha', '5.0.8', '103449');

    installerDataSvc.addItemToInstall(VirtualBoxInstall.KEY, vbox);
  });

  afterEach(function() {
    sandbox.restore();
  });

  describe('constrution', function() {
    it('should verify existing files', function() {
      let stub = sandbox.stub(installerDataSvc, 'verifyFiles').returns();
      new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(stub).calledOnce;
    });

    it('should register an event handler for 3 different events', function() {
      sandbox.stub(installerDataSvc, 'verifyFiles').returns();
      let tron = {
        ipcRenderer: {
          setMaxListeners: function() {},
          on: function() {}
        }
      };

      let spy = sandbox.spy(tron.ipcRenderer, 'on');
      new InstallController({}, {}, installerDataSvc, tron, window);

      expect(spy).calledThrice;
      expect(spy).calledWith('checkComplete');
      expect(spy).calledWith('downloadingComplete');
      expect(spy).calledWith('installComplete');
    });
  });

  describe('verifyFiles', function() {
    let verifyStub;

    beforeEach(function() {
      verifyStub = sandbox.stub(installerDataSvc, 'verifyExistingFiles').returns();
    });

    it('should select component for file verification if some of its files are downloaded', function() {
      vbox.files.virtualbox.downloaded = true;
      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWith(ctrl.itemProgress, 'virtualbox');
    });

    it('should skip a component if none of its files are downloaded', function() {
      vbox.files.virtualbox.downloaded = false;
      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWithExactly(ctrl.itemProgress);
    });

    it('should skip a component if it is bundled', function() {
      vbox.files.virtualbox.downloaded = true;
      vbox.downloadedFile = vbox.bundledFile;
      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWithExactly(ctrl.itemProgress);
    });

    it('should work for multiple components', function() {
      vbox.files.virtualbox.downloaded = true;
      let jdk = new JdkInstall(installerDataSvc, 'jdk8', 'downloadUrl', 'fileName', 'sha256sum');
      installerDataSvc.addItemToInstall('jdk', jdk);
      jdk.files.jdk.downloaded = true;

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);

      expect(verifyStub).calledOnce;
      expect(verifyStub).calledWith(ctrl.itemProgress, 'virtualbox', 'jdk');
    });
  });

  describe('downloadFiles', function() {
    let dlStub, progressStub;

    beforeEach(function() {
      sandbox.stub(installerDataSvc, 'verifyExistingFiles').returns();
      dlStub = sandbox.stub(installerDataSvc, 'download').returns();
      progressStub = sandbox.stub(ProgressState.prototype, 'setTotalAmount').returns();
    });

    it('should process components that require download', function() {
      let jdk = new JdkInstall(installerDataSvc, 'jdk8', 'downloadUrl', 'fileName', 'sha256sum');
        installerDataSvc.addItemToInstall('jdk', jdk);
      vbox.downloaded = false;
      jdk.downloaded = true;

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);
      installerDataSvc.downloadFiles(ctrl.itemProgress, window.navigator.userAgent);

      expect(dlStub).calledOnce;
      expect(dlStub).calledWithExactly(ctrl.itemProgress, 1, window.navigator.userAgent, 'virtualbox');
    });

    it('should set the total amount to the sum of file sizes', function() {
      vbox.useDownload = true;
      vbox.files.foo = {
        dmUrl: 'downloadUrl',
        fileName: 'foo.bar',
        sha256sum: 'sum',
        size: 123
      };

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);
      installerDataSvc.downloadFiles(ctrl.itemProgress, ctrl.$window.navigator.userAgent);

      expect(progressStub).calledOnce;
      expect(progressStub).calledWith(vbox.files.virtualbox.size + vbox.files.foo.size);
    });

    it('should set total download count to number of pending files', function() {
      let jdk = new JdkInstall(installerDataSvc, 'jdk8', 'downloadUrl', 'fileName', 'sha256sum');
      installerDataSvc.addItemToInstall('jdk', jdk);
      jdk.useDownload = true;
      vbox.useDownload = true;
      vbox.files.foo = {
        dmUrl: 'downloadUrl',
        fileName: 'foo.bar',
        sha256sum: 'sum',
        size: 123
      };

      let ctrl = new InstallController({}, {}, installerDataSvc, new ElectronMock(), window);
      installerDataSvc.downloadFiles(ctrl.itemProgress, ctrl.$window.navigator.userAgent);

      expect(dlStub).calledOnce;
      expect(dlStub).calledWithExactly(ctrl.itemProgress, 3, ctrl.$window.navigator.userAgent, 'virtualbox', 'jdk');
    });
  });

  describe('triggerInstall', function() {
    let vboxStub, doneStub;

    beforeEach(function() {
      sandbox.stub(vbox, 'isDownloadRequired').returns(false);
      vboxStub = sandbox.stub(vbox, 'install').yields();
      doneStub = sandbox.stub(installerDataSvc, 'installDone').returns();
    });

    it.skip('logs error in case of install failed', function() {
      vbox.install.restore();
      sandbox.stub(vbox, 'install').callsArgWith(2, 'Error');
      new InstallController({}, timeoutStub, installerDataSvc, new ElectronMock());
      expect(errorStub).calledTwice;
    });

    it.skip('should call the installables install method', function() {
      sandbox.stub(installerDataSvc, 'startInstall').returns();

      new InstallController({}, timeoutStub, installerDataSvc, new ElectronMock());
      expect(vboxStub).calledOnce;
    });

    it.skip('should call data services installDone when install finishes', function() {
      sandbox.stub(installerDataSvc, 'startInstall').returns();

      new InstallController({}, timeoutStub, installerDataSvc, new ElectronMock());

      expect(doneStub).calledOnce;
      expect(doneStub).calledWith(sinon.match.any, 'virtualbox');
    });
  });

  describe('ProgressState', function() {
    it('should set default min/max values when passed to constructor', function() {
      let progress = new ProgressState('key', 'prodName', 'prodVersion', 'productDesc', {}, sinon.stub(), 100, 1000);
      expect(progress.min).equals(100);
      expect(progress.max).equals(1000);
    });
    describe('setTotalDownloadSize', function() {
      it('should set totalSize property value', function() {
        let progress = new ProgressState();
        progress.setTotalAmount(1000);
        expect(progress.totalAmount).to.be.equal(1000);
      });
    });
    describe('setCurrent', function() {
      describe('should update', function() {
        let progress;
        beforeEach(function() {
          progress = new ProgressState();
          progress.$timeout = sinon.stub();
          progress.$scope = {$apply:sinon.stub()};
          progress.setStatus('Downloading');
          progress.setTotalAmount(1000);
          progress.setCurrent(100);
        });
        it('current progress amount value', function() {
          expect(progress.currentAmount).equals(100);
        });
        it('current prcentage', function() {
          expect(progress.current).equals(10);
        });
        it('lable value', function() {
          expect(progress.label).to.have.string(
            progress.sizeInKB(progress.currentAmount) + ' / ' + progress.sizeInKB(progress.totalAmount) + ' (' + progress.current + '%)'
          );
        });
        it('ETA to second', function() {
          sinon.stub(progress, 'calculateTime').returns(1000);
          progress.setCurrent(101);
          expect(progress.label).to.have.string('sec');
        });
        it('ETA to seconds', function() {
          sinon.stub(progress, 'calculateTime').returns(45000);
          progress.setCurrent(102);
          expect(progress.label).to.have.string('secs');
        });
        it('ETA to minute', function() {
          sinon.stub(progress, 'calculateTime').returns(65000);
          progress.setCurrent(103);
          expect(progress.label).to.have.string('min');
        });
        it('ETA to minutes', function() {
          sinon.stub(progress, 'calculateTime').returns(125000);
          progress.setCurrent(104);
          expect(progress.label).to.have.string('mins');
        });
        it('ETA to hour', function() {
          sinon.stub(progress, 'calculateTime').returns(3600000);
          progress.setCurrent(105);
          expect(progress.label).to.have.string('hr');
        });
        it('ETA to hours', function() {
          sinon.stub(progress, 'calculateTime').returns(7200000);
          progress.setCurrent(106);
          expect(progress.label).to.have.string('hrs');
        });
        it('ETA to day', function() {
          sinon.stub(progress, 'calculateTime').returns(3600000*24);
          progress.setCurrent(105);
          expect(progress.label).to.have.string('day');
        });
        it('ETA to days', function() {
          sinon.stub(progress, 'calculateTime').returns(7200000*24);
          progress.setCurrent(106);
          expect(progress.label).to.have.string('days');
        });
        it('ETA to year', function() {
          sinon.stub(progress, 'calculateTime').returns(3600000*24*366);
          progress.setCurrent(105);
          expect(progress.label).to.have.string('year');
        });
        it('ETA to years', function() {
          sinon.stub(progress, 'calculateTime').returns(7200000*24*366);
          progress.setCurrent(106);
          expect(progress.label).to.have.string('years');
        });

      });
    });
    describe('setStatus', function() {
      let progress;
      beforeEach(function() {
        progress = new ProgressState();
        progress.$timeout = sinon.stub();
        progress.$scope = {$apply:sinon.stub()};
      });
      it('does nothing if status is the same', function() {
        progress.current = 1;
        progress.setStatus('');
        expect(progress.current).equals(1);
      });
    });
    describe('setComplete', function() {
      let progress;
      before(function() {
        progress = new ProgressState();
        progress.$timeout = sinon.stub();
        progress.$scope = {$apply:sinon.stub()};
        progress.setTotalAmount(1000);
        progress.setCurrent(100);
        progress.setComplete();
      });
      it('sets status to "Complete"', function() {
        expect(progress.status).equals('Complete');
      });
    });
    describe('calculateTime', function() {
      let progress;
      beforeEach(function() {
        progress = new ProgressState();
        progress.lastTime = 100000;
        progress.totalAmount = 9000000;
        progress.currentAmount = 400000;
        sandbox.stub(Date.prototype, 'getTime').returns(101000);
      });

      it('returns time estimate based on average speed', function() {
        expect(progress.calculateTime()).to.equal((9000000 - 400000) / 400);
      });

      it('uses exponential moving average speed', function() {
        progress.averageSpeed = 800;

        //average speed moves with a smoothing factor
        let result = progress.calculateTime();
        expect(progress.averageSpeed).to.equal(0.15 * 400 + 0.85 * 800);
        expect(result).to.equal((9000000 - 400000) / (0.15 * 400 + 0.85 * 800));
      });
    });

    describe('resetTime', function() {
      it('resets speed and time calculation', function() {
        let progress = new ProgressState();
        progress.lastTime = 100000;
        progress.lastSpeed = 1000;
        progress.averageSpeed = 100;
        progress.totalAmount = 9000000;
        progress.currentAmount = 400000;

        progress.resetTime();

        expect(progress.lastSpeed).to.equal(0);
        expect(progress.lastAmount).to.equal(progress.currentAmount);
        expect(progress.averageSpeed).to.equal(0);
      });
    });

    describe('exit', function() {
      it('exit closes active window', function() {
        let electron = new ElectronMock();
        sandbox.stub(installerDataSvc, 'verifyFiles').returns();
        sandbox.stub(electron.remote.currentWindow);
        let installController = new InstallController({}, {}, installerDataSvc, electron, window);
        installController.exit();
        expect(electron.remote.currentWindow.close).calledOnce;
      });
    });
  });

  it.skip('downloadAgain closes dialog with error and start download for failed installers', function() {
    sandbox.stub(InstallableItem.prototype, 'downloadInstaller');
    sandbox.stub(InstallableItem.prototype, 'restartDownload').returns();

    let scopeStub = {
      $apply: function(callback) {
        callback && callback();
      }
    };

    let timeoutStub = function(callback) {
      callback && callback();
    };

    let installCtrl = new InstallController(scopeStub, timeoutStub, installerDataSvc, new ElectronMock());
    sandbox.spy(installCtrl, 'closeDownloadAgainDialog');
    installCtrl.downloadAgain();
    expect(InstallableItem.prototype.restartDownload).calledOnce;
    expect(installCtrl.closeDownloadAgainDialog).calledOnce;
  });
});
<|endoftext|>