<commit_before>odoo.define('web.restrict_export_sidebar', function (require) {
    "use strict";

    var core = require('web.core');
    var Sidebar = require('web.Sidebar');
    var _t = core._t;
    var QWeb = core.qweb;

    // Extend Sidebar module, can be found in 'web/static/src/js/widgets/sidebar.js'
    Sidebar.include({
        add_items: function(section_code, items) {
            if (section_code != 'other' || !this.session) {
                return this._super(section_code, items);
            }

            var self = this;
            var _super = self._super;
            var args = arguments;

            $.when(
                // Also allows a special user group "Export" to export data.
                this.session.user_has_group('export_no_allowed.group_export')
            ).done(function(is_user, is_admin, can_export) {
                if (is_user && (can_export || is_admin)) {
                    _super.apply(self, args);
                }
                else {
                    var export_label = _t('Export');
                    for (var i = 0; i < items.length; i++) {
                        if (items[i]['label'] == export_label) {
                            items.splice(i, 1);
                        };
                    };
                    return _super.apply(self, args);
                }
            });

        },

    });
});
<commit_msg>[FIX] - export_not_allowed: Fixed error that not allowed see the button with the permission.<commit_after>odoo.define('web.restrict_export_sidebar', function (require) {
    "use strict";

    var core = require('web.core');
    var Sidebar = require('web.Sidebar');
    var _t = core._t;
    var QWeb = core.qweb;

    // Extend Sidebar module, can be found in 'web/static/src/js/widgets/sidebar.js'
    Sidebar.include({
        add_items: function(section_code, items) {
            if (section_code != 'other' || !this.session) {
                return this._super(section_code, items);
            }

            var self = this;
            var _super = self._super;
            var args = arguments;

            $.when(
                this.session.user_has_group('base.group_user'),
                this.session.user_has_group('export_no_allowed.group_export')
            ).done(function(is_user, can_export) {
                if (is_user && can_export ) {
                    _super.apply(self, args);
                }
                else {
                    var export_label = _t('Export');
                    for (var i = 0; i < items.length; i++) {
                        if (items[i]['label'] == export_label) {
                            items.splice(i, 1);
                        };
                    };
                    return _super.apply(self, args);
                }
            });

        },

    });
});
<|endoftext|>


<commit_before>
require('../images/radar_legend.png');
require('../src/stylesheets/base.scss');

const d3 = require('d3');
const createRadar = require('../index');

const radarData = [
  {
    "name": "Hammer",
    "ring": "use",
    "quadrant": "Tools",
    "isNew": true,
    "description": "Good tool to get nails into walls."
  },
  {
    "name": "Nail",
    "ring": "try",
    "quadrant": "Technology",
    "isNew": "TRUE",
    "description": "Good technology to mount something on walls."
  },
  {
    "name": "Glueing",
    "ring": "avoid",
    "quadrant": "Method",
    "isNew": "False",
    "description": "I don't have good experiences with glueing things together."
  },
  {
    "name": "NPM",
    "ring": "use",
    "quadrant": "Platform",
    "isNew": false,
    "description": "Well-known node package repository."
  },
];

createRadar(radarData);<commit_msg>Added further usage hints as comments in the sample<commit_after>
require('../images/radar_legend.png');
require('../src/stylesheets/base.scss');

// in your project, use the following line to include stylesheet information
// require('../node_modules/techradar/src/stylesheets/base.scss');
// make sure to proceess it to css as part of your build procedure, e.g. with webpack

const createRadar = require('../index');
//replace with require('techradar') when using the npm package 'techradar' in your project

const radarData = [
  {
    "name": "Hammer",
    "ring": "use",
    "quadrant": "Tools",
    "isNew": true,
    "description": "Good tool to get nails into walls."
  },
  {
    "name": "Nail",
    "ring": "try",
    "quadrant": "Technology",
    "isNew": "TRUE",
    "description": "Good technology to mount something on walls."
  },
  {
    "name": "Glueing",
    "ring": "avoid",
    "quadrant": "Method",
    "isNew": "False",
    "description": "I don't have good experiences with glueing things together."
  },
  {
    "name": "NPM",
    "ring": "use",
    "quadrant": "Platform",
    "isNew": false,
    "description": "Well-known node package repository."
  },
];

createRadar(radarData);<|endoftext|>


<commit_before>/**
 * System configuration for Angular 2 samples
 * Adjust as necessary for your application needs.
 */
(function(global) {
  // map tells the System loader where to look for things
  var map = {
	'@angular':                   'node_modules/@angular',
	'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
	'rxjs':                       'node_modules/rxjs'
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
	'app':                        { main: 'main.js',  defaultExtension: 'js' },
	'rxjs':                       { defaultExtension: 'js' },
	'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
  };
  var ngPackageNames = [
	'common',
	'compiler',
	'core',
	'forms',
	'http',
	'platform-browser',
	'platform-browser-dynamic',
	'router',
	'router-deprecated',
	'upgrade',
  ];
  // Individual files (~300 requests):
  function packIndex(pkgName) {
	packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
  }
  // Bundled (~40 requests):
  function packUmd(pkgName) {
	packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
  }
  // Most environments should use UMD; some (Karma) need the individual index files
  var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
  // Add package entries for angular packages
  ngPackageNames.forEach(setPackageConfig);
  var config = {
	map: map,
	packages: packages
  };
  System.config(config);
})(this);
<commit_msg>Also commit system.js config<commit_after>/**
 * System configuration for Angular 2 samples
 * Adjust as necessary for your application needs.
 */
(function(global) {
  // map tells the System loader where to look for things
  var map = {
	'app':                        'dist/app',
	'@angular':                   'node_modules/@angular',
	'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
	'rxjs':                       'node_modules/rxjs'
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
	'app':                        { main: 'main.js',  defaultExtension: 'js' },
	'rxjs':                       { defaultExtension: 'js' },
	'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
  };
  var ngPackageNames = [
	'common',
	'compiler',
	'core',
	'forms',
	'http',
	'platform-browser',
	'platform-browser-dynamic',
	'router',
	'router-deprecated',
	'upgrade',
  ];
  // Individual files (~300 requests):
  function packIndex(pkgName) {
	packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
  }
  // Bundled (~40 requests):
  function packUmd(pkgName) {
	packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
  }
  // Most environments should use UMD; some (Karma) need the individual index files
  var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
  // Add package entries for angular packages
  ngPackageNames.forEach(setPackageConfig);
  var config = {
	map: map,
	packages: packages
  };
  System.config(config);
})(this);
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

/* More information about these options at jshint.com/docs/options */
/* exported GumHandler */
'use strict';

function GumHandler() {
  this.gumPendingDialog_ = document.getElementById('gum-pending-dialog');
  this.gumErrorDialog_ = document.getElementById('gum-error-dialog');
  this.gumNotSupportedDialog_ = document.getElementById('gum-not-supported-dialog');
  this.gumErrorMessage_ = document.getElementById('gum-error-message');
  this.firstUserCheck_ = null;
  this.gumStreamSuccessCallback_ = null;
}

GumHandler.prototype = {
  start: function(callback) {
    this.gumStreamSuccessCallback_ = callback;
    if (typeof navigator.getUserMedia === 'undefined') {
      this.gumNotSupportedDialog_.open();
    } else {
      this.getUserMedia_(callback);
      this.firstUserCheck_ = setTimeout(this.firstTimeUser_.bind(this), 300);
    }
  },

  firstTimeUser_: function() {
    this.gumPendingDialog_.open();
  },

  getUserMedia_: function() {
    doGetUserMedia({audio: true, video: true}, this.gotStream_.bind(this),
        this.gotError_.bind(this));
  },

  gotStream_: function(stream) {
    clearTimeout(this.firstUserCheck_);

    // Stop all tracks to ensure the camera and audio devices are shutdown directly.
    for (var i = 0; i < stream.getTracks().length; i++) {
      stream.getTracks()[i].stop();
    }
    this.gumPendingDialog_.close();
    this.gumErrorDialog_.close();
    this.gumStreamSuccessCallback_();
  },

  gotError_: function(error) {
    clearTimeout(this.firstUserCheck_);
    this.gumPendingDialog_.close();
    this.gumErrorMessage_.innerHTML = error.name;
    this.gumErrorDialog_.open();
    setTimeout(this.getUserMedia_.bind(this), 1000);
  }
};
<commit_msg>gumhandler.js<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

/* More information about these options at jshint.com/docs/options */
/* exported GumHandler */
'use strict';

function GumHandler() {
  this.gumPendingDialog_ = document.getElementById('gum-pending-dialog');
  this.gumErrorDialog_ = document.getElementById('gum-error-dialog');
  this.gumNotSupportedDialog_ =
      document.getElementById('gum-not-supported-dialog');
  this.gumErrorMessage_ = document.getElementById('gum-error-message');
  this.firstUserCheck_ = null;
  this.gumStreamSuccessCallback_ = null;
}

GumHandler.prototype = {
  start: function(callback) {
    this.gumStreamSuccessCallback_ = callback;
    if (typeof navigator.getUserMedia === 'undefined') {
      this.gumNotSupportedDialog_.open();
    } else {
      this.getUserMedia_(callback);
      this.firstUserCheck_ = setTimeout(this.firstTimeUser_.bind(this), 300);
    }
  },

  firstTimeUser_: function() {
    this.gumPendingDialog_.open();
  },

  getUserMedia_: function() {
    doGetUserMedia({audio: true, video: true}, this.gotStream_.bind(this),
        this.gotError_.bind(this));
  },

  gotStream_: function(stream) {
    clearTimeout(this.firstUserCheck_);

    // Stop all tracks to ensure the camera and audio devices are shutdown
    // directly.
    for (var i = 0; i < stream.getTracks().length; i++) {
      stream.getTracks()[i].stop();
    }
    this.gumPendingDialog_.close();
    this.gumErrorDialog_.close();
    this.gumStreamSuccessCallback_();
  },

  gotError_: function(error) {
    clearTimeout(this.firstUserCheck_);
    this.gumPendingDialog_.close();
    this.gumErrorMessage_.innerHTML = error.name;
    this.gumErrorDialog_.open();
    setTimeout(this.getUserMedia_.bind(this), 1000);
  }
};
<|endoftext|>


<commit_before>const _add = ( arr, state) => {
	let o = {};
	o[state.next ? 'next' : 'any'] = state.expr ? state.expr : '*';
	if (state.filter.length() > 0) o.filter = state.filter.getValue();
	arr.push(o);
	state.filter = new Filter();
	state.expr = '';
	state.next = false;
}

function Filter(){
	this.value= [];
	this.active = undefined;
}
Filter.prototype.newFilter = function(){
	if (this.isActive()) throw new Error("[ inside filter");
	this.active = this.value.length;
	this.value[this.active] = "";
}
Filter.prototype.addChar = function(ch){
	if (!this.isActive()) throw new Error("filter was not started by [");
	this.value[this.active] = this.value[this.active] + ch;
}
Filter.prototype.closeFilter = function(){
	if (!this.isActive()) throw new Error("] outside filter");
	this.active = undefined;
}
Filter.prototype.length = function() {
	return this.value.length;
}
Filter.prototype.isActive = function() {
	return (typeof this.active!= 'undefined' );
}
Filter.prototype.getValue = function() {
	let ret = [];
	//trim'em'all
	for (let i=0; i<this.value.length; i++) ret.push(this.value[i].trim());
	return ret;
}

//returns array of {<type>:<string>, [filter=<string>]} where <type>=next|any (and 'filter' field is not mandandatory)
//for instance, "a.b"       becomes [{any:'a'}, {next:'b'}]
//              ".a[x=1] b" becomes [{next:'a', filter:'x=1'}, {any:'b'}]
const parse = (str) => {
	if (typeof str != 'string') str=str+'';
	let ret = [];

	let state = {filter:new Filter(), expr:'', next:false};
	for (let i in str) {
		if ((i==0 || str[i-1] != '\\') && str[i] === '[') {
			state.filter.newFilter();
		} else
		if ((i==0 || str[i-1] != '\\') && str[i] === ']') {
			state.filter.closeFilter();
		} else
		if ((i==0 || str[i-1] != '\\') && str[i] === '.') {
			if (state.filter.isActive()) {
				state.filter.addChar(str[i]);
			} else if (state.expr || state.filter.length() > 0) {
				_add(ret, state);
				state.next = true;
			} else {
				//start of the line or some error (double dot etc.)
				if (ret.length==0) {
					state.next = true;
				} else {
					throw new Error('parse error: nothing before dot');
				}
			}
		} else
		if ((i==0 || str[i-1] != '\\') && str[i] === ' ') {
			if (state.filter.isActive()) {
				state.filter.addChar(str[i]);
			} else if (state.expr || state.filter.length() > 0) {
				_add(ret, state);
			} else {
				//do nothing - it's just double space
			}
		} else {
			if (state.filter.length() > 0) {
				state.filter.addChar(str[i]);
			} else {
				state.expr = state.expr + str[i];
			}
		}
	}
	if (state.expr || state.filter.length() > 0) {
		_add(ret, state);
	}
	return ret;
}

//returns {left:<left_side>, right:<right_side>, delimiter:<delimiter>}
//for instance, "a\\=b=c" becomes {left:'a=b', right:'c', delimiter:'='}
const parse_filter = (str) => {
	if (typeof str != 'string') str=str+'';
	let ret = {left:''};

	for (let i=0; i < str.length; i++) {
		if (str[i] == '=' && (i==0 || str[i-1] != '\\' )) {
			ret.delimiter = "=";
			ret.right = str.substring(i+1).trim();
			break;
		} else {
			ret.left = ret.left + str[i];
		}
	}
	ret.left = ret.left.replace("\\=", "=").trim();
	if (ret.right) ret.right = ret.right.replace("\\=", "=");
	return ret;
}

module.exports = {parse, parse_filter};
<commit_msg>add different types of filters<commit_after>const { operator } = require('./parser_operators');
const operator_keys = Object.keys(operator);
operator_keys.sort((a,b)=>{return b.length - a.length});

function Filter(){
	this.value= [];
	this.active = undefined;
}
Filter.prototype.newFilter = function(){
	if (this.isActive()) throw new Error("[ inside filter");
	this.active = this.value.length;
	this.value[this.active] = "";
}
Filter.prototype.addChar = function(ch){
	if (!this.isActive()) throw new Error("filter was not started by [");
	this.value[this.active] = this.value[this.active] + ch;
}
Filter.prototype.closeFilter = function(){
	if (!this.isActive()) throw new Error("] outside filter");
	this.active = undefined;
}
Filter.prototype.length = function() {
	return this.value.length;
}
Filter.prototype.isActive = function() {
	return (typeof this.active!= 'undefined' );
}
Filter.prototype.getValue = function() {
	let ret = [];
	//trim'em'all
	for (let i=0; i<this.value.length; i++) ret.push(this.value[i].trim());
	return ret;
}

const _add = ( arr, state) => {
	let o = {};
	o[state.next ? 'next' : 'any'] = state.expr ? state.expr : '*';
	if (state.filter.length() > 0) o.filter = state.filter.getValue();
	arr.push(o);
	state.filter = new Filter();
	state.expr = '';
	state.next = false;
}

//returns array of {<type>:<string>, [filter=<string>]} where <type>=next|any (and 'filter' field is not mandandatory)
//for instance, "a.b"       becomes [{any:'a'}, {next:'b'}]
//              ".a[x=1] b" becomes [{next:'a', filter:'x=1'}, {any:'b'}]
const parse = (str) => {
	if (typeof str != 'string') str=str+'';
	let ret = [];

	let state = {filter:new Filter(), expr:'', next:false};
	for (let i in str) {
		if ((i==0 || str[i-1] != '\\') && str[i] === '[') {
			state.filter.newFilter();
		} else
		if ((i==0 || str[i-1] != '\\') && str[i] === ']') {
			state.filter.closeFilter();
		} else
		if ((i==0 || str[i-1] != '\\') && str[i] === '.') {
			if (state.filter.isActive()) {
				state.filter.addChar(str[i]);
			} else if (state.expr || state.filter.length() > 0) {
				_add(ret, state);
				state.next = true;
			} else {
				//start of the line or some error (double dot etc.)
				if (ret.length==0) {
					state.next = true;
				} else {
					throw new Error('parse error: nothing before dot');
				}
			}
		} else
		if ((i==0 || str[i-1] != '\\') && str[i] === ' ') {
			if (state.filter.isActive()) {
				state.filter.addChar(str[i]);
			} else if (state.expr || state.filter.length() > 0) {
				_add(ret, state);
			} else {
				//do nothing - it's just double space
			}
		} else {
			if (state.filter.length() > 0) {
				state.filter.addChar(str[i]);
			} else {
				state.expr = state.expr + str[i];
			}
		}
	}
	if (state.expr || state.filter.length() > 0) {
		_add(ret, state);
	}
	return ret;
}

//returns {left:<left_side>, right:<right_side>, delimiter:<delimiter>}
//for instance, "a\\=b=c" becomes {left:'a=b', right:'c', delimiter:'='}
const parse_filter = (str) => {
	if (typeof str != 'string') str=str+'';
	let ret = {left:''};

	for (let i=0; i < str.length; i++) {
		let op = _is_operator(str, i);
		if (op) {
			ret.delimiter = op;
			ret.right = str.substring(i + 1);
			ret.left = str.substring(0, i-op.length+1);
			break;
		}
	}
	if (!ret.right) ret.left = str;

	ret.left = _replace_escaped_operators(ret.left);
	if (ret.right) ret.right = _replace_escaped_operators(ret.right);

	return ret;
}

const _replace_escaped_operators = (str) => {
	let ret = str.trim();
	operator_keys.forEach(_itm => {
		ret = ret.replace("\\"+_itm, _itm);
	})
	return ret;
}

const _is_operator = (str, str_index) => {
	let ret;
	for (let i=0; i<operator_keys.length && !ret; i++){
		let op = _is_operator_word(str, str_index, operator_keys[i]);
		if (op) ret = operator_keys[i];
	}
	return ret;
}

const _is_operator_word = (str, str_index, word) => {
	let ret = false;
	if (str_index>=word.length-1) {
		let word_index = 0;
		while (word_index<word.length-1 && str[str_index-word_index] == word[word.length-1-word_index]) word_index++;
		if (word_index == word.length-1 && str[str_index-word_index] == word[word.length-1-word_index]) {
			if (str_index==word.length-1) {
				ret = true;
			} else {
				if (str[str_index-1] != '\\' ) {
					ret = true;
				}
			}
		}
	}
	return ret;
}

module.exports = {parse, parse_filter};
<|endoftext|>


<commit_before>/// Recursive Descent Parser
//https://www.youtube.com/watch?v=SH5F-rwWEog&t=3m12s

(function IIFE ( parser ) {

    var Clock = window.Clock
    var expression = "[var_name]+3==5>=87"

    var result
    Clock.time( "Parse", function () {
        result = parser( expression )
    } )

    console.log( "Expression:", expression )
    console.log( result )

})(function parser ( expression ) {

    var exp = expression
    var token = ""
    var L = ""      //current letter
    var i = 0       //index
    var stack = []

    return (function Main() {
        next()
        START()
        return POP()
    })()

    ///Parser
    ;function START() {
        MATH_EXPRESSION()
        CONDITION()
        return
    }

    ;function CONDITION() {
        if ( isOperatorConditionStart( L ) ) {
            OPERATOR_CONDITION()
            PUSH()

            MATH_EXPRESSION()
            CONDITION()

            CONDITION_ONE_SEMANTIC()
        }

        return
    }

    ;function MATH_EXPRESSION() {
        TOKEN()
        MATH()
        return
    }

    ;function MATH() {
        if ( isOperatorMath( L ) ) {
            match( isOperatorMath )
            PUSH()

            TOKEN()
            MATH()

            MATH_ONE_SEMANTIC()
        }

        return
    }

    ;function TOKEN() {
        if ( isDigit( L ) ) {
            match( isDigit )
            NUMBER()
        } else if ( L === "." ) {
            match( "." )
            RATIONAL()
        } else if ( L === "'" ) {
            match( "'" )
            STRING()
            match( "'" )
        } else if ( L === "[" ) {
            match( "[" )
            VAR()

            if ( L !== "]" ) {
                throwExpectingError( "TOKEN", "lowercase letter [a..z], '_', or ']'", i )
            }
            match( "]" )
        } else {
            throwExpectingError( "TOKEN", "number, string, or variable", i )
        }

        PUSH()
        return
    }

    ;function NUMBER() {
        if ( isDigit( L ) ) {
            match( isDigit )
            NUMBER()
        } else if ( L === "." ) {
            match( "." )
            RATIONAL()
        }

        return
    }

    ;function RATIONAL() {
        if ( isDigit(L) ) {
            match( isDigit )
            RATIONAL()
        }

        return
    }

    ;function STRING() {
        if ( L === "'" ) {
            //Add later?
            /*
            match( "'" )

            if ( L === "'" ) {
                match( "'" )
                STRING()
            }
            */
        } else {
            match( L )
            STRING()
        }

        return
    }

    ;function VAR() {
        if ( isLowerCaseLetter( L ) ) {
            match( isLowerCaseLetter )
            VAR_NAME()
        } else {
            throwExpectingError( "VAR", "lowercase letter [a..z]", i )
        }

        return
    }

    ;function VAR_NAME() {
        if ( isLowerCaseLetter( L ) ) {
            match( isLowerCaseLetter )
            VAR_NAME()
        } else if ( L === "_" ) {
            match( "_" )
            VAR_NAME()
        }

        return
    }

    ;function OPERATOR_CONDITION() {
        if ( L === "=" ) {
            match( "=" )

            if ( L === "=" ) {
                match( "=" )
            } else {
                throwExpectingError( "OPERATOR_CONDITION", "'='", i )
            }
        } else if ( L === "!" ) {
            match( "!" )

            if ( L === "=" ) {
                match( "=" )
            } else {
                throwExpectingError( "OPERATOR_CONDITION", "'='", i )
            }
        } else if ( L === "<" ) {
            match( "<" )

            if ( L === "=" ) {
                match( "=" )
            }
        } else if ( L === ">" ) {
            match( ">" )

            if ( L === "=" ) {
                match( "=" )
            }
        } else {
            throwExpectingError( "OPERATOR_CONDITION", "'=', '!', '<', or '>'", i )
        }

        return
    }

    ///Semantics
    ;function PUSH( item ) {
        if ( item != null ) {
            stack.push( item )
        } else if ( token.trim() !== "" ) {
            stack.push( token )
            token = ""
        }
    }

    ;function POP() {
        return stack.pop()
    }

    ;function CREATE_NODE( operator, left, right ) {
        return {
            operator: operator,
            left: left,
            right: right,
        }
    }

    ;function CONDITION_ONE_SEMANTIC() {
        var right = POP()
        var operator = POP()
        var left = POP()
        var node = CREATE_NODE( operator, left, right )
        PUSH( node )
    }

    ;function MATH_ONE_SEMANTIC() {
        var right = POP()
        var operator = POP()
        var left = POP()
        var node = CREATE_NODE( operator, left, right )
        PUSH( node )
    }

    ///Helpers
    ;function isDigit( letter ) {
        var number
        if ( typeof letter === "string" ) {
            number = parseInt( letter )
        } else if ( typeof letter === "number" ) {
            number = letter
        }

        return isNaN( number ) === false
            && typeof number === "number"
    }

    ;function isLowerCaseLetter( letter ) {
        //TODO: Refactor - Use character codes.
        var lowerCaseLetters = [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" ]
        return lowerCaseLetters.includes( letter )
    }

    ;function isOperatorConditionStart( letter ) {
        var operatorConditionStart = [ "=", "!", "<", ">" ]
        return operatorConditionStart.includes( letter )
    }

    ;function isOperatorMath( letter ) {
        var operatorMath = [ "+", "-", "*", "/", "%" ]
        return operatorMath.includes( letter )
    }

    ;function match( item ) {
        var isCorrect = ( typeof item === "function" && item( L ) )
            || ( Array.isArray( item ) && item.includes( L ) )
            || ( item === L )
        if ( isCorrect ) {
            next()
            return true
        } else {
            throwError( "There was a mismatch", i )
        }
    }

    ;function next() {
        token += L
        L = exp[ i++ ]
    }

    ///ERROR Handling
    ;function throwError( message, index ) {
        var firstPart = "%c" + exp.substring( 0, index - 1 )
        var letter = "%c" + exp.substring( index - 1, index )
        var secondPart = "%c" + exp.substring( index )
        var fontSize = "font-size: 16px;"
        var partCss = "color:grey;" + fontSize
        var letterCss = "color:white;" + fontSize
        console.info( firstPart + letter + secondPart , partCss, letterCss, partCss )

        var error = new Error( message )
        throw error
    }

    ;function throwExpectingError( functionName, expecting, index ) {
        var message = "In function '"
            + functionName + "', expecting a(n) "
            + expecting + " at character "
            + index + ".";

        throwError( message, index )
    }

})

<commit_msg>Added whitespace ignorer.<commit_after>/// Recursive Descent Parser
//https://www.youtube.com/watch?v=SH5F-rwWEog&t=3m12s

(function IIFE ( parser ) {

    var Clock = window.Clock
    var expression = "   [var_name]  +   2 ==  5  >=   87   "

    var result
    Clock.time( "Parse", function () {
        result = parser( expression )
    } )

    console.log( "Expression:", expression )
    console.log( result )

})(function parser ( expression ) {

    var exp = expression
    var token = ""
    var L = ""      //current letter
    var i = 0       //index
    var stack = []

    return (function Main() {
        appendAndNext()
        START()
        return POP()
    })()

    ///Parser
    ;function START() {
        MATH_EXPRESSION()
        CONDITION()
        return
    }

    ;function CONDITION() {
        if ( isOperatorConditionStart( L ) ) {
            OPERATOR_CONDITION()
            PUSH()

            MATH_EXPRESSION()
            CONDITION()

            CONDITION_ONE_SEMANTIC()
        }

        return
    }

    ;function MATH_EXPRESSION() {
        TOKEN()
        MATH()
        return
    }

    ;function MATH() {
        if ( isOperatorMath( L ) ) {
            match( isOperatorMath )
            PUSH()

            TOKEN()
            MATH()

            MATH_ONE_SEMANTIC()
        }

        return
    }

    ;function TOKEN() {
        ignoreWhitespaces()

        if ( isDigit( L ) ) {
            match( isDigit )
            NUMBER()
        } else if ( L === "." ) {
            match( "." )
            RATIONAL()
        } else if ( L === "'" ) {
            match( "'" )
            STRING()
            match( "'" )
        } else if ( L === "[" ) {
            match( "[" )
            VAR()

            if ( L !== "]" ) {
                throwExpectingError( "TOKEN", "lowercase letter [a..z], '_', or ']'", i )
            }
            match( "]" )
        } else {
            throwExpectingError( "TOKEN", "number, string, or variable", i )
        }
        ignoreWhitespaces()

        PUSH()
        return
    }

    ;function NUMBER() {
        if ( isDigit( L ) ) {
            match( isDigit )
            NUMBER()
        } else if ( L === "." ) {
            match( "." )
            RATIONAL()
        }

        return
    }

    ;function RATIONAL() {
        if ( isDigit(L) ) {
            match( isDigit )
            RATIONAL()
        }

        return
    }

    ;function STRING() {
        if ( L === "'" ) {
            //Add later?
            /*
            match( "'" )

            if ( L === "'" ) {
                match( "'" )
                STRING()
            }
            */
        } else {
            match( L )
            STRING()
        }

        return
    }

    ;function VAR() {
        if ( isLowerCaseLetter( L ) ) {
            match( isLowerCaseLetter )
            VAR_NAME()
        } else {
            throwExpectingError( "VAR", "lowercase letter [a..z]", i )
        }

        return
    }

    ;function VAR_NAME() {
        if ( isLowerCaseLetter( L ) ) {
            match( isLowerCaseLetter )
            VAR_NAME()
        } else if ( L === "_" ) {
            match( "_" )
            VAR_NAME()
        }

        return
    }

    ;function OPERATOR_CONDITION() {
        if ( L === "=" ) {
            match( "=" )

            if ( L === "=" ) {
                match( "=" )
            } else {
                throwExpectingError( "OPERATOR_CONDITION", "'='", i )
            }
        } else if ( L === "!" ) {
            match( "!" )

            if ( L === "=" ) {
                match( "=" )
            } else {
                throwExpectingError( "OPERATOR_CONDITION", "'='", i )
            }
        } else if ( L === "<" ) {
            match( "<" )

            if ( L === "=" ) {
                match( "=" )
            }
        } else if ( L === ">" ) {
            match( ">" )

            if ( L === "=" ) {
                match( "=" )
            }
        } else {
            throwExpectingError( "OPERATOR_CONDITION", "'=', '!', '<', or '>'", i )
        }

        return
    }

    ///Semantics
    ;function PUSH( item ) {
        if ( item != null ) {
            stack.push( item )
        } else if ( token.trim() !== "" ) {
            stack.push( token )
            token = ""
        }
    }

    ;function POP() {
        return stack.pop()
    }

    ;function CREATE_NODE( operator, left, right ) {
        return {
            operator: operator,
            left: left,
            right: right,
        }
    }

    ;function CONDITION_ONE_SEMANTIC() {
        var right = POP()
        var operator = POP()
        var left = POP()
        var node = CREATE_NODE( operator, left, right )
        PUSH( node )
    }

    ;function MATH_ONE_SEMANTIC() {
        var right = POP()
        var operator = POP()
        var left = POP()
        var node = CREATE_NODE( operator, left, right )
        PUSH( node )
    }

    ///Helpers
    ;function ignoreWhitespaces() {
        while( L === " " ) {
            next()
        }
    }

    ;function isDigit( letter ) {
        var number
        if ( typeof letter === "string" ) {
            number = parseInt( letter )
        } else if ( typeof letter === "number" ) {
            number = letter
        }

        return isNaN( number ) === false
            && typeof number === "number"
    }

    ;function isLowerCaseLetter( letter ) {
        //TODO: Refactor - Use character codes.
        var lowerCaseLetters = [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" ]
        return lowerCaseLetters.includes( letter )
    }

    ;function isOperatorConditionStart( letter ) {
        var operatorConditionStart = [ "=", "!", "<", ">" ]
        return operatorConditionStart.includes( letter )
    }

    ;function isOperatorMath( letter ) {
        var operatorMath = [ "+", "-", "*", "/", "%" ]
        return operatorMath.includes( letter )
    }

    ;function match( item ) {
        var isCorrect = ( typeof item === "function" && item( L ) )
            || ( Array.isArray( item ) && item.includes( L ) )
            || ( item === L )
        if ( isCorrect ) {
            appendAndNext()
        } else {
            throwError( "There was a mismatch", i )
        }
    }

    ;function next() {
        L = exp[ i++ ]
    }

    ;function appendAndNext() {
        token += L
        next()
    }

    ///ERROR Handling
    ;function throwError( message, index ) {
        var firstPart = "%c" + exp.substring( 0, index - 1 )
        var letter = "%c" + exp.substring( index - 1, index)
        var secondPart = "%c" + exp.substring( index )
        var fontSize = "font-size: 16px;"
        var partCss = "color:grey;" + fontSize
        var letterCss = "color:white;" + fontSize
        console.info( firstPart + letter + secondPart , partCss, letterCss, partCss )

        var error = new Error( message )
        throw error
    }

    ;function throwExpectingError( functionName, expecting, index ) {
        var message = "In function '"
            + functionName + "', expecting a(n) "
            + expecting + " at character "
            + index + ".";

        throwError( message, index )
    }

})

<|endoftext|>


<commit_before>var fs = require('fs');

var crc = require('crc');

var inputFile = process.argv[2];

if (!inputFile) {
  console.error('Usage: node parser.js <path to ublue_setup.gen.out.txt>');
  process.exit(1);
}

if (!fs.existsSync(inputFile)) {
  console.error('Input file "%s" doesn\'t exits!', inputFile);
  process.exit(1);
}

// console.info('Input file = %s', inputFile);

var input = fs.readFileSync(inputFile).toString();

input = input.replace(/\n|\r/g, '');
input = input.replace(/.+\[Setup Data\] /, '');
input = input.replace(/-/g, '');

// console.log('Input = %s', input);

var inputBuffer = new Buffer(input, 'hex');

var setupMessages = [];

var i = 0;

// seperate the setup messages
while (i < inputBuffer.length) {
  var length = inputBuffer.readUInt8(i);

  setupMessages.push(inputBuffer.slice(i, i + length + 1));

  i += (length + 1);
}

// group setup messages by type
var setupMessagesByType = {};

for (var i = 0; i < setupMessages.length; i++) {
  var setupMessage = setupMessages[i];

  var length = setupMessage.readUInt8(0);
  var type = setupMessage.readUInt8(2);
  var data = setupMessage.slice(4);

  if (setupMessagesByType[type] === undefined) {
    setupMessagesByType[type] = [];
  }

  setupMessagesByType[type].push(data);
}

// combine setup messages by type
var setupMessageDataByType = {};

for (var i in setupMessagesByType) {
  setupMessageDataByType[i] = Buffer.concat(setupMessagesByType[i]);

  setupMessageDataByType[i] = setupMessageDataByType[i].slice(0, setupMessageDataByType[i].length - 1);
}

console.log('GATT');

var gattData = setupMessageDataByType[32];

i = 0;
while (i < gattData.length) {
  var properties = gattData[i];
  i++;

  var permissions = gattData[i];
  i++;

  var length = gattData[i];
  i++;

  var valueLength = gattData[i];
  i++;

  var handle = gattData.readUInt16BE(i);
  i += 2;

  var uuid = gattData.readUInt16BE(i);
  i += 2;

  var spacer = gattData[i];
  i++;

  var dataLength = (properties === 6) ? valueLength : length;
  var data = gattData.slice(i, i + dataLength);
  i += dataLength;

  console.log('\tproperties = %d', properties);
  console.log('\tpermissions = %d', permissions);
  console.log('\tlength = %d', length);
  console.log('\tvalue length = %d', valueLength);
  console.log('\thandle = 0x%s', handle.toString(16));
  console.log('\tuuid = 0x%s', uuid.toString(16));
  console.log('\tdata = %s', data.toString('hex'));

  if (uuid === 0x2800) {
    // service
    console.log('\t\tservice: 0x%s', data.readUInt16LE(0).toString(16));
  } else if (uuid === 0x2803) {
    // characteristic
    console.log('\t\tcharacteristic: 0x%s', data.readUInt16LE(3).toString(16));
    console.log('\t\tvalue handle: 0x%s', data.readUInt16LE(1).toString(16));
  } else {
    // value
    console.log('\t\tvalue = %s', data.toString('hex'));
  }

  console.log();
}

// crc
var crc = crc.crc16ccitt(inputBuffer.slice(0, inputBuffer.length - 2));
var expectedCrc = inputBuffer.slice(inputBuffer.length - 2).toString('hex');

console.log('crc = %s %s', crc.toString(16), expectedCrc);
<commit_msg>- support parsing 128-bit uuid's<commit_after>var fs = require('fs');

var crc = require('crc');

var inputFile = process.argv[2];

if (!inputFile) {
  console.error('Usage: node parser.js <path to ublue_setup.gen.out.txt>');
  process.exit(1);
}

if (!fs.existsSync(inputFile)) {
  console.error('Input file "%s" doesn\'t exits!', inputFile);
  process.exit(1);
}

// console.info('Input file = %s', inputFile);

var input = fs.readFileSync(inputFile).toString();

input = input.replace(/\n|\r/g, '');
input = input.replace(/.+\[Setup Data\] /, '');
input = input.replace(/-/g, '');

// console.log('Input = %s', input);

var inputBuffer = new Buffer(input, 'hex');

var setupMessages = [];

var i = 0;

// seperate the setup messages
while (i < inputBuffer.length) {
  var length = inputBuffer.readUInt8(i);

  setupMessages.push(inputBuffer.slice(i, i + length + 1));

  i += (length + 1);
}

// group setup messages by type
var setupMessagesByType = {};

for (var i = 0; i < setupMessages.length; i++) {
  var setupMessage = setupMessages[i];

  var length = setupMessage.readUInt8(0);
  var type = setupMessage.readUInt8(2);
  var data = setupMessage.slice(4);

  if (setupMessagesByType[type] === undefined) {
    setupMessagesByType[type] = [];
  }

  setupMessagesByType[type].push(data);
}

// combine setup messages by type
var setupMessageDataByType = {};

for (var i in setupMessagesByType) {
  setupMessageDataByType[i] = Buffer.concat(setupMessagesByType[i]);

  setupMessageDataByType[i] = setupMessageDataByType[i].slice(0, setupMessageDataByType[i].length - 1);
}

console.log('GATT');

var gattData = setupMessageDataByType[32];

i = 0;
while (i < gattData.length) {
  var properties = gattData[i];
  i++;

  var permissions = gattData[i];
  i++;

  var length = gattData[i];
  i++;

  var valueLength = gattData[i];
  i++;

  var handle = gattData.readUInt16BE(i);
  i += 2;

  var uuid = gattData.readUInt16BE(i);
  i += 2;

  var spacer = gattData[i];
  i++;

  var dataLength = (properties === 6) ? valueLength : length;
  var data = gattData.slice(i, i + dataLength);
  i += dataLength;

  console.log('\tproperties = %d', properties);
  console.log('\tpermissions = %d', permissions);
  console.log('\tlength = %d', length);
  console.log('\tvalue length = %d', valueLength);
  console.log('\thandle = 0x%s', handle.toString(16));
  console.log('\tuuid = 0x%s', uuid.toString(16));
  console.log('\tdata = %s', data.toString('hex'));

  if (uuid === 0x2800) {
    // service
    console.log('\t\tservice: 0x%s', data.toString('hex').match(/.{1,2}/g).reverse().join(''));
  } else if (uuid === 0x2803) {
    // characteristic
    console.log('\t\tcharacteristic: 0x%s', data.slice(3).toString('hex').match(/.{1,2}/g).reverse().join(''));
    console.log('\t\tvalue handle: 0x%s', data.readUInt16LE(1).toString(16));
  } else {
    // value
    console.log('\t\tvalue = %s', data.toString('hex'));
  }

  console.log();
}

// crc
var crc = crc.crc16ccitt(inputBuffer.slice(0, inputBuffer.length - 2));
var expectedCrc = inputBuffer.slice(inputBuffer.length - 2).toString('hex');

console.log('crc = %s %s', crc.toString(16), expectedCrc);
<|endoftext|>


<commit_before>const match = s =>
  r => {
    const test = r.exec(s)
    console.log(test)
    return (test && test.length > 1) ? r.exec(s)[1] : '0'
  }

const parse = module.exports = (innerText, target) => {

  const data = innerText
    .split('\n')
    .map(t => t.trim())

  const head = /(.*)\s\(Period\s(\d)\)\s(.*)/.exec(data[data.indexOf('Summary') - 1]) || '....'
  const info = {
    name: head[1],
    period: head[2],
    instructor: head[3]
  }

  const report = data.reduce((grades, l, i) => {

    if (!/^\d{1,2}\/\d{1,2}\/\d{1,2}/.test(l))
      return grades

    if (/^weighted/.test(data[i - 1])) {

      const info = data[i - 1]
      const getInfo = match(info)
      grades.current = data[i - 2]

      grades[grades.current] = {
        score      : getInfo(/(\d+|\*)\sout\sof\s\d+/),
        total      : getInfo(/\d+|\*\sout\sof\s(\d+)/),
        weight     : getInfo(/(\d+.\d+)%/),
        assignments: []
      }
    }

    const getGrade = match(l)

    grades[grades.current].assignments.push({
      name : l.split('\t')[1],
      date : getGrade(/^(\d{1,2}\/\d{1,2}\/\d{1,2})/),
      score: getGrade(/(\d+|\*)\sout\sof\s\d+/),
      total: getGrade(/\d+|\*\sout\sof\s(\d+)/)
    })

    return grades
  }, {})

  delete report.current

  return {
    course: info,
    report: report
  }
}
<commit_msg>Having trouble with Regex<commit_after>const match = s =>
  r => {
    const test = r.exec(s)
    console.log(test)
    return (test && test.length > 1 && test[1] != 'undefined') ? test[1] : '0'
  }

const parse = module.exports = (innerText, target) => {

  const data = innerText
    .split('\n')
    .map(t => t.trim())

  const head = /(.*)\s\(Period\s(\d)\)\s(.*)/.exec(data[data.indexOf('Summary') - 1]) || '....'
  const info = {
    name: head[1],
    period: head[2],
    instructor: head[3]
  }

  const report = data.reduce((grades, l, i) => {

    if (!/^\d{1,2}\/\d{1,2}\/\d{1,2}/.test(l))
      return grades

    if (/^weighted/.test(data[i - 1])) {

      const info = data[i - 1]
      const getInfo = match(info)
      grades.current = data[i - 2]

      grades[grades.current] = {
        score      : getInfo(/([\d\*]+)\sout\sof\s\d+/),
        total      : getInfo(/[\d\*]+\sout\sof\s(\d+)/),
        weight     : getInfo(/(\d+.\d+)%/),
        assignments: []
      }
    }

    const getGrade = match(l)

    grades[grades.current].assignments.push({
      name : l.split('\t')[1],
      date : getGrade(/^(\d{1,2}\/\d{1,2}\/\d{1,2})/),
      score: getGrade(/(\d+|\*)\sout\sof\s\d+/),
      total: getGrade(/\d+|\*\sout\sof\s(\d+)/)
    })

    return grades
  }, {})

  delete report.current

  return {
    course: info,
    report: report
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

require('proof')(6, function (step, deepEqual) {
  var fs = require('fs'), cadence = require('../..');

  cadence(function (step) {

    step(function () {
      return 1;
    });

  })(function (error, result) {

    deepEqual(result, 1, "step");

  });

  cadence(function (step) {

    step(function () {
      step(function () {
        step()(new Error('errored'));
      });
    }, function () {
      throw new Error('should not be called');
    });

  })(function (error) {

    deepEqual(error.message, 'errored', 'error');

  });

  cadence(function (step) {

    [ 1, 2, 3 ].forEach(step([], function (number) {
      item(number, step());
    }, function (number) {
      return - number;
    }));

  }, function (items) {

    deepEqual(items, [ -1, -2, -3 ], 'step arrayed');

  })(step());

  cadence(function (step) {

    [].forEach(step([], function (number) {
      item(number, step());
    }, function (number) {
      return - number;
    }));

  }, function (items) {

    deepEqual(items, [], 'step arrayed empty');

  })(step());

  cadence(function (step) {

    [ 1, 2, 3 ].forEach(step([], function (number) {
      if (number % 2) step()(null, number);
      else step()(null);
    }));

  }, function (items) {

    deepEqual(items, [ 1, 3 ], 'step arrayed missing');

  })(step());

  cadence(function (step) {

    [ 1 ].forEach(step([], function (number) {
      step(function () {}, function () { return number });
    }));

  }, function (items) {

    deepEqual(items, [ 1 ], 'step arrayed single');

  })(step());

});

function item (value, callback) {
  process.nextTick(function () { callback(null, value) });
}

<commit_msg>Add test for sub-cadence error handling.<commit_after>#!/usr/bin/env node

require('proof')(7, function (step, deepEqual) {
  var fs = require('fs'), cadence = require('../..');

  cadence(function (step) {

    step(function () {
      return 1;
    });

  })(function (error, result) {

    deepEqual(result, 1, "step");

  });

  cadence(function (step) {

    step(function () {
      step(function () {
        step()(new Error('errored'));
      });
    }, function () {
      throw new Error('should not be called');
    });

  })(function (error) {

    deepEqual(error.message, 'errored', 'error');

  });

  cadence(function (step) {

    step(function () {
      step(Error, function () {
        step()(new Error('errored'));
      });
    }, function (error) {
      deepEqual(error.message, 'errored', 'error caught');
    });

  })(step());

  cadence(function (step) {

    [ 1, 2, 3 ].forEach(step([], function (number) {
      item(number, step());
    }, function (number) {
      return - number;
    }));

  }, function (items) {

    deepEqual(items, [ -1, -2, -3 ], 'step arrayed');

  })(step());

  cadence(function (step) {

    [].forEach(step([], function (number) {
      item(number, step());
    }, function (number) {
      return - number;
    }));

  }, function (items) {

    deepEqual(items, [], 'step arrayed empty');

  })(step());

  cadence(function (step) {

    [ 1, 2, 3 ].forEach(step([], function (number) {
      if (number % 2) step()(null, number);
      else step()(null);
    }));

  }, function (items) {

    deepEqual(items, [ 1, 3 ], 'step arrayed missing');

  })(step());

  cadence(function (step) {

    [ 1 ].forEach(step([], function (number) {
      step(function () {}, function () { return number });
    }));

  }, function (items) {

    deepEqual(items, [ 1 ], 'step arrayed single');

  })(step());

});

function item (value, callback) {
  process.nextTick(function () { callback(null, value) });
}

<|endoftext|>


<commit_before>define([], function() {
    return [
        "alert(\"Hello, world!\")",
        "1 + 1",
        "function my_add(a, b) { return a + b }\n\nmy_add(2, 3)\n",
        "// You will have to reload the editor or use the inspector to remove this widget\nvar state = {\n    count: 0,\n    inc: function() {state.count++}\n}\n\nvar Counter = {\n    view: function() {\n        return m(\"div\", {onclick: state.inc}, state.count)\n    }\n}\n\nvar div = document.createElement(\"div\")\ndocument.body.appendChild(div)\nm.mount(div, Counter)",
        "var div = document.createElement(\"div\")\n\nvar state = {\n    count: 0,\n    inc: function() {state.count++}\n}\n\nvar Counter = {\n    view: function() {\n        return m(\"div\",\n            m(\"button\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n            m(\"div\", {onclick: state.inc}, state.count)\n        )\n    }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, Counter)",
        "var div = document.createElement(\"div\")\n\nvar state = {\n    count: 0,\n    inc: function() {state.count++}\n}\n\nvar Counter = {\n    view: function() {\n        return m(\"div.ba.ma3.pa3.bg-light-purple\",\n            m(\"button.fr\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n            m(\"div\", {onclick: state.inc}, state.count)\n        )\n    }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, Counter)",
        "let div = document.createElement(\"div\")\n \nlet counter = 0\n\nfunction testButtonClicked(increment) {\n    console.log(\"testButtonClicked\")\n    counter += increment\n}\n\nconst MyComponent = {\n  view(controller, args) {\n    return m(\"div.ba.ma3.pa3.bg-light-purple\",\n      m(\"button.fr\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n      \"Hello world!\",\n      m(\"br\"),\n      \"counter: \" + counter,\n      m(\"button\", {onclick: testButtonClicked.bind(null, -1)}, \"-\"),\n      m(\"button\", {onclick: testButtonClicked.bind(null, 1)}, \"+\")\n    )\n  }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, MyComponent)\n",
        "let div = document.createElement(\"div\")\n \nconst MyComponent = {\n  view(controller, args) {\n    return m(\"div.ba.ma3.pa3.bg-light-purple\",\n      m(\"button.fr\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n      m(\"iframe\", {src: \"http://www.calphysics.org/haisch/Patent%207379286\", width: 800, height: 600})\n    )\n  }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, MyComponent)\n",
        "// Use the \"show\" convenience function to display a view made by a Mithril-generating function.\n// You can add extra Tachyons.js styling for the enclosing div as an optional second parameter.\nshow(() => {\n    return m(\"button.bg-red.pa2.br4\", { onclick: () => alert(\"Hello world\") }, \"Hello\")\n  }, \".bg-blue.br4\"\n)",
        "const draggables = { \n    1: {x: 0, y: 0},\n    2: {x: 0, y: 0},\n    3: {x: 0, y: 0},\n    4: {x: 0, y: 0},\n}\n\nlet dragStart\n\nshow(() => {\n    return m(\"div.bg-gray.h5.w100\", { ondragover: (e) => e.preventDefault(), ondrop: (e) => e.preventDefault() },\n        Object.keys(draggables).map((number) => m(\"div.di.ba.pa2.ma2.relative.bg-green\", {\n            draggable: true,\n            style: {\n                cursor: \"move\",\n                top: draggables[number].y + \"px\",\n                left: draggables[number].x + \"px\",\n            },\n            ondragstart: (e) => {\n                dragStart = {x: e.x, y: e.y}\n                e.dataTransfer.setData('text/plain', number)\n                e.dataTransfer.effectAllowed = \"move\"\n            },\n            ondragend: (e) => {\n                const d = draggables[number]\n                const s = dragStart;\n                draggables[number] = {x: d.x + e.x - s.x, y: d.y + e.y - s.y}\n            },\n            onclick: () => alert(\"Hello from draggable #\" + number)\n        }, \"Drag me! \" + number))\n      )\n    }, \".bg-blue.br4\"\n)",
        "let temperature_F\nlet temperature_C\n\nfunction inputF(event) {\n    temperature_F = event.target.value;\n    if (temperature_F.trim() === \"\") { temperature_C = \"\"; return }\n    temperature_C = \"\" + ((parseFloat(temperature_F) - 32) * 5 / 9)\n}\n\nfunction inputC(event) {\n    temperature_C = event.target.value;\n    if (temperature_C.trim() === \"\") { temperature_F = \"\"; return }\n    temperature_F = \"\" + (parseFloat(temperature_C) * 9 / 5 + 32)\n}\n\nshow(() => {\n    return m(\"div\", [\n        \"Fahrenheight\",\n        m(\"input.ma2\", { value: temperature_F, oninput: inputF }),\n        \"Celcius\",\n        m(\"input.ma2\", { value: temperature_C, oninput: inputC })\n    ])\n  }, \".bg-blue.br4\"\n)",
        "// Derived from three.js example: https://www.npmjs.com/package/three\n\nrequirejs([\"vendor/three\"], function(three) {\n    var scene, camera, renderer\n    var geometry, material, mesh\n    \n    function init(width, height) {\n     \n        scene = new THREE.Scene()\n     \n        camera = new THREE.PerspectiveCamera( 75, width / height, 1, 10000 )\n        camera.position.z = 1000\n     \n        geometry = new THREE.BoxGeometry( 200, 200, 200 )\n        material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } )\n     \n        mesh = new THREE.Mesh( geometry, material )\n        scene.add( mesh )\n     \n        renderer = new THREE.WebGLRenderer()\n        renderer.setSize( width, height )\n     \n        return renderer.domElement\n    }\n    \n    let animating = false\n    \n    function animate() {\n        if (!animating) { return }\n        \n        requestAnimationFrame( animate )\n        \n        mesh.rotation.x += 0.01\n        mesh.rotation.y += 0.02\n        \n        renderer.render( scene, camera )\n    }\n    \n    function animateStart() {\n        animating = true\n        animate()\n    }\n    \n    function animateStop() {\n        animating = false\n    }\n    \n    show(() => {\n            return m(\"div\", {\n                id: \"test\",\n                style: {\n                    width: \"25rem\",\n                    height: \"25rem\",\n                },\n                oncreate(vnode) {\n                    vnode.dom.appendChild(init(vnode.dom.offsetWidth, vnode.dom.offsetHeight))\n                    animateStart()\n                },\n                onremove(vnode) {\n                    animateStop()\n                }\n            })\n        },\n        \".bg-green.br4\"\n    )\n})",
    ]
})
<commit_msg>Improve dragging example for Firefox<commit_after>define([], function() {
    return [
        "alert(\"Hello, world!\")",
        "1 + 1",
        "function my_add(a, b) { return a + b }\n\nmy_add(2, 3)\n",
        "// You will have to reload the editor or use the inspector to remove this widget\nvar state = {\n    count: 0,\n    inc: function() {state.count++}\n}\n\nvar Counter = {\n    view: function() {\n        return m(\"div\", {onclick: state.inc}, state.count)\n    }\n}\n\nvar div = document.createElement(\"div\")\ndocument.body.appendChild(div)\nm.mount(div, Counter)",
        "var div = document.createElement(\"div\")\n\nvar state = {\n    count: 0,\n    inc: function() {state.count++}\n}\n\nvar Counter = {\n    view: function() {\n        return m(\"div\",\n            m(\"button\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n            m(\"div\", {onclick: state.inc}, state.count)\n        )\n    }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, Counter)",
        "var div = document.createElement(\"div\")\n\nvar state = {\n    count: 0,\n    inc: function() {state.count++}\n}\n\nvar Counter = {\n    view: function() {\n        return m(\"div.ba.ma3.pa3.bg-light-purple\",\n            m(\"button.fr\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n            m(\"div\", {onclick: state.inc}, state.count)\n        )\n    }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, Counter)",
        "let div = document.createElement(\"div\")\n \nlet counter = 0\n\nfunction testButtonClicked(increment) {\n    console.log(\"testButtonClicked\")\n    counter += increment\n}\n\nconst MyComponent = {\n  view(controller, args) {\n    return m(\"div.ba.ma3.pa3.bg-light-purple\",\n      m(\"button.fr\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n      \"Hello world!\",\n      m(\"br\"),\n      \"counter: \" + counter,\n      m(\"button\", {onclick: testButtonClicked.bind(null, -1)}, \"-\"),\n      m(\"button\", {onclick: testButtonClicked.bind(null, 1)}, \"+\")\n    )\n  }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, MyComponent)\n",
        "let div = document.createElement(\"div\")\n \nconst MyComponent = {\n  view(controller, args) {\n    return m(\"div.ba.ma3.pa3.bg-light-purple\",\n      m(\"button.fr\", {onclick: function () { m.mount(div, null); document.body.removeChild(div) } }, \"X\"),\n      m(\"iframe\", {src: \"http://www.calphysics.org/haisch/Patent%207379286\", width: 800, height: 600})\n    )\n  }\n}\n\ndocument.body.appendChild(div)\nm.mount(div, MyComponent)\n",
        "// Use the \"show\" convenience function to display a view made by a Mithril-generating function.\n// You can add extra Tachyons.js styling for the enclosing div as an optional second parameter.\nshow(() => {\n    return m(\"button.bg-red.pa2.br4\", { onclick: () => alert(\"Hello world\") }, \"Hello\")\n  }, \".bg-blue.br4\"\n)",
        "// Dragging example works in Firefox but has an offset issue with Chrome\n\nconst draggables = { \n    1: {x: 0, y: 0},\n    2: {x: 0, y: 0},\n    3: {x: 0, y: 0},\n    4: {x: 0, y: 0},\n}\n\nlet dragStart\n\nshow(() => {\n    return m(\"div.bg-gray.h5.w100\", { ondragover: (e) => e.preventDefault(), ondrop: (e) => e.preventDefault() },\n        Object.keys(draggables).map((number) => m(\"div.di.ba.pa2.ma2.relative.bg-green\", {\n            draggable: true,\n            style: {\n                cursor: \"move\",\n                top: draggables[number].y + \"px\",\n                left: draggables[number].x + \"px\",\n            },\n            ondragstart: (e) => {\n                dragStart = {x: e.screenX, y: e.screenY}\n                console.log(\"ondragstart\", dragStart, e)\n                e.dataTransfer.setData('text/plain', number)\n                e.dataTransfer.effectAllowed = \"move\"\n            },\n            ondragend: (e) => {\n                const d = draggables[number]\n                console.log(\"ondragend d\", d)\n                const s = dragStart;\n                console.log(\"ondragend s\", s)\n                draggables[number] = {x: d.x + e.screenX - s.x, y: d.y + e.screenY - s.y}\n                console.log(\"ondragend\", draggables[number])\n            },\n            onclick: () => alert(\"Hello from draggable #\" + number)\n        }, \"Drag me! \" + number))\n      )\n    }, \".bg-blue.br4\"\n)",
        "let temperature_F\nlet temperature_C\n\nfunction inputF(event) {\n    temperature_F = event.target.value;\n    if (temperature_F.trim() === \"\") { temperature_C = \"\"; return }\n    temperature_C = \"\" + ((parseFloat(temperature_F) - 32) * 5 / 9)\n}\n\nfunction inputC(event) {\n    temperature_C = event.target.value;\n    if (temperature_C.trim() === \"\") { temperature_F = \"\"; return }\n    temperature_F = \"\" + (parseFloat(temperature_C) * 9 / 5 + 32)\n}\n\nshow(() => {\n    return m(\"div\", [\n        \"Fahrenheight\",\n        m(\"input.ma2\", { value: temperature_F, oninput: inputF }),\n        \"Celcius\",\n        m(\"input.ma2\", { value: temperature_C, oninput: inputC })\n    ])\n  }, \".bg-blue.br4\"\n)",
        "// Derived from three.js example: https://www.npmjs.com/package/three\n\nrequirejs([\"vendor/three\"], function(three) {\n    var scene, camera, renderer\n    var geometry, material, mesh\n    \n    function init(width, height) {\n     \n        scene = new THREE.Scene()\n     \n        camera = new THREE.PerspectiveCamera( 75, width / height, 1, 10000 )\n        camera.position.z = 1000\n     \n        geometry = new THREE.BoxGeometry( 200, 200, 200 )\n        material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } )\n     \n        mesh = new THREE.Mesh( geometry, material )\n        scene.add( mesh )\n     \n        renderer = new THREE.WebGLRenderer()\n        renderer.setSize( width, height )\n     \n        return renderer.domElement\n    }\n    \n    let animating = false\n    \n    function animate() {\n        if (!animating) { return }\n        \n        requestAnimationFrame( animate )\n        \n        mesh.rotation.x += 0.01\n        mesh.rotation.y += 0.02\n        \n        renderer.render( scene, camera )\n    }\n    \n    function animateStart() {\n        animating = true\n        animate()\n    }\n    \n    function animateStop() {\n        animating = false\n    }\n    \n    show(() => {\n            return m(\"div\", {\n                id: \"test\",\n                style: {\n                    width: \"25rem\",\n                    height: \"25rem\",\n                },\n                oncreate(vnode) {\n                    vnode.dom.appendChild(init(vnode.dom.offsetWidth, vnode.dom.offsetHeight))\n                    animateStart()\n                },\n                onremove(vnode) {\n                    animateStop()\n                }\n            })\n        },\n        \".bg-green.br4\"\n    )\n})",
    ]
})
<|endoftext|>


<commit_before>import client from './client';
import ClientModule from './ClientModule';

import View from './display/View';
import SquaredView from './display/SquaredView';
import SpaceView from './display/SpaceView';
import TouchSurface from './display/TouchSurface';

/**
 * [client] Allow to indicate the approximate location of the client on a map.
 *
 * The module always has a view (that displays the map and a button to validate the location) and requires the SASS partial `_77-locator.scss`.
 *
 * The module finishes its initialization after the user confirms his / her approximate location by clicking on the “Validate” button.
 *
 * (See also {@link src/server/ServerLocator.js~ServerLocator} on the server side.)
 *
 * @example
 * const locator = new ClientLocator();
 */
export default class ClientLocator extends ClientModule {
  /**
   * @param {Object} [options={}] - Options.
   * @param {String} [options.name='locator'] - Name of the module.
   * @param {Boolean} [options.showBackground=false] - Indicates whether to show the space background image or not.
   */
  constructor(options = {}) {
    super(options.name || 'locator', options);

    this._attachArea = this._attachArea.bind(this);
    this._onAreaTouchStart = this._onAreaTouchStart.bind(this);
    this._onAreaTouchMove = this._onAreaTouchMove.bind(this);
    this._sendCoordinates = this._sendCoordinates.bind(this);

    this._positionRadius = options.positionRadius || 0.3;
    this.spaceCtor = options.spaceCtor || SpaceView;
    this.viewCtor = options.viewCtor || SquaredView;
    this.init();
  }

  init() {
    this.content.activateBtn = false;
    this.view = this.createView();
  }

  /**
   * Start the module.
   * @private
   */
  start() {
    super.start();

    this.send('request');
    this.receive('area', this._attachArea, false);
  }

  /**
   * Done method.
   * Remove the `'resize'` listener on the `window`.
   * @private
   */
  done() {
    super.done();
  }

  /**
   * Create a SpaceView and display it in the square section of the view
   */
  _attachArea(area) {
    this.area = area;
    this.space = new this.spaceCtor(area, {}, { isSubView: true });
    // @todo - find a way to remove these hardcoded selectors
    this.view.setViewComponent('.section-square', this.space);
    this.view.render('.section-square');
    // touchSurface on $svg
    this.surface = new TouchSurface(this.space.$svg);
    this.surface.addListener('touchstart', this._onAreaTouchStart);
    this.surface.addListener('touchmove', this._onAreaTouchMove);
  }

  _onAreaTouchStart(id, normX, normY) {
    // if (id !== 0) { return; } // does not work in Safari
    // -> how to prevent multitouch ?

    if (!this.position) {
      this._createPosition(normX, normY);

      this.content.activateBtn = true;
      this.view.render('.section-float');
      this.view.installEvents({
        'click .btn': this._sendCoordinates,
      })
    } else {
      this._updatePosition(normX, normY);
    }
  }

  _onAreaTouchMove(id, normX, normY) {
    // if (id !== 0) { return; } // does not work in Safari
    this._updatePosition(normX, normY);
  }

  _createPosition(normX, normY) {
    this.position = {
      id: 'locator',
      x: normX * this.area.width,
      y: normY * this.area.height,
      radius: this._positionRadius,
    }

    this.space.addPoint(this.position);
  }

  _updatePosition(normX, normY) {
    this.position.x = normX * this.area.width;
    this.position.y = normY * this.area.height;

    this.space.updatePoint(this.position);
  }

  _sendCoordinates() {
    const $btn = this.view.$el.querySelector('.btn');
    $btn.setAttribute('disabled', true);

    client.coordinates = this.position;
    this.send('coordinates', client.coordinates);
    this.done();
  }
}
<commit_msg>added `random` and `persist` options (for development purposes)<commit_after>import client from './client';
import ClientModule from './ClientModule';
import localStorage from './localStorage';
import View from './display/View';
import SquaredView from './display/SquaredView';
import SpaceView from './display/SpaceView';
import TouchSurface from './display/TouchSurface';

/**
 * [client] Allow to indicate the approximate location of the client on a map.
 *
 * The module always has a view (that displays the map and a button to validate the location) and requires the SASS partial `_77-locator.scss`.
 *
 * The module finishes its initialization after the user confirms his / her approximate location by clicking on the “Validate” button.
 *
 * (See also {@link src/server/ServerLocator.js~ServerLocator} on the server side.)
 *
 * @example
 * const locator = new ClientLocator();
 */
export default class ClientLocator extends ClientModule {
  /**
   * @param {Object} [options={}] - Options.
   * @param {String} [options.name='locator'] - The name of the module.
   * @param {Boolean} [options.random=false] - Send random position to the server and call `this.done()` (for developpement purpose)
   * @param {Boolean} [options.persist=false] - If set to `true`, store the normalized coordinates in `localStorage` and retrieve them in subsequent calls. Delete the stored position when set to `false`. (for developpement purpose)
   */
  constructor(options = {}) {
    super(options.name || 'locator', options);

    this._random = options.random || false;
    this._persist = options.persist || false;
    this._positionRadius = options.positionRadius || 0.3;
    this.spaceCtor = options.spaceCtor || SpaceView;
    this.viewCtor = options.viewCtor || SquaredView;

    // The namespace where coordinates are stored when `options.persist = true`.
    this._localStorageNamespace = `soundworks:${this.name}`;

    this._onAreaTouchStart = this._onAreaTouchStart.bind(this);
    this._onAreaTouchMove = this._onAreaTouchMove.bind(this);

    this.init();
  }

  init() {
    this.content.activateBtn = false;
    this.view = this.createView();
  }

  /**
   * Start the module.
   * @private
   */
  start() {
    super.start();

    this.send('request');

    if (!this._persist)
      localStorage.delete(this._localStorageNamespace);

    this.receive('area', (area) => {
      this._attachArea(area);

      // Bypass the locator according to module configuration options.
      // If `options.random` is set to true, use random coordinates.
      // If `options.persist` is set to true use coordinates stored in local storage,
      // do nothing when no coordinates are stored yet.
      if (this._random || this._persist) {
        let coords;

        if (this._random) {
          coords.normX = Math.random();
          coords.normY = Math.random();
        } else if (this._persist) {
          coords = JSON.parse(localStorage.get(this._localStorageNamespace));
        }

        if (coords !== null) {
          this._createPosition(coords.normX, coords.normY);
          this._sendCoordinates();
        }
      }
    });
  }

  /**
   * Create a `SpaceView` and display it in the square section of the view
   */
  _attachArea(area) {
    this.area = area;
    this.space = new this.spaceCtor(area, {}, { isSubView: true });
    // @todo - find a way to remove these hardcoded selectors
    this.view.setViewComponent('.section-square', this.space);
    this.view.render('.section-square');
    // touchSurface on $svg
    this.surface = new TouchSurface(this.space.$svg);
    this.surface.addListener('touchstart', this._onAreaTouchStart);
    this.surface.addListener('touchmove', this._onAreaTouchMove);
  }

  _onAreaTouchStart(id, normX, normY) {
    // if (id !== 0) { return; } // does not work in Safari -> how to prevent multitouch ?
    if (!this.position) {
      this._createPosition(normX, normY);

      this.content.activateBtn = true;
      this.view.render('.section-float');
      this.view.installEvents({
        'click .btn': (e) => {
          e.target.setAttribute('disabled', true);
          this._sendCoordinates();
        },
      });
    } else {
      this._updatePosition(normX, normY);
    }
  }

  _onAreaTouchMove(id, normX, normY) {
    this._updatePosition(normX, normY);
  }

  _createPosition(normX, normY) {
    this.position = {
      id: 'locator',
      x: normX * this.area.width,
      y: normY * this.area.height,
      radius: this._positionRadius,
    }

    this.space.addPoint(this.position);
  }

  _updatePosition(normX, normY) {
    this.position.x = normX * this.area.width;
    this.position.y = normY * this.area.height;

    this.space.updatePoint(this.position);
  }

  _sendCoordinates() {
    if (this._persist) { // store normalized coordinates
      const normX = this.position.x / this.area.width;
      const normY = this.position.y / this.area.height;
      localStorage.set(this._localStorageNamespace, JSON.stringify({ normX, normY }));
    }

    client.coordinates = this.position;
    this.send('coordinates', client.coordinates);
    this.done();
  }
}
<|endoftext|>


<commit_before>\    var retry = 0;
    var socket;
    function connect(url) {
      retry++;
      socket = io.connect( url, { reconnection: false } );
      setTimeout(function() {
        if (!socket.connected) {
          log('Unable to connect (' + retry + ').  Retrying in 10 seconds');
          setTimeout(function() { connect(url) }, 10000);
        } else {
          log('Connected on attempt (' + retry + ')');
          socket.on('disconnect', function() { retry = 0; connect(url) });
          socket.on('bom-do', function (data) {
            console.log('got bom-do message');
            bomDo(data);
          });
        }
      }, 250);
    }
    connect('http://localhost:3033');

    function bomDo(data) {
      console.log('++++ bomDo');
      var command = data.command;
      console.log('++++ command = ' + JSON.stringify(command));
      if (command.type == 'SET-INPUT-VAL') {
        console.log('++++ command.css = ' + command.css);
        var domEle = $(command.css);
        if (!domEle) {
          socket.emit(command.msgId, { command: command, success: false, details: 'No matching elements for ' + command.css });
        } else {
          var currentVal = $(domEle).val();
          // clear out the current contents of the input field
          for (var val_i=0; val_i<currentVal.length; val_i++) {
          console.log('      _ backspacing...');
            $(domEle).sendkeys ('{backspace}');
          }
          console.log('     _ sending ' + command.val);
          $(domEle).sendkeys (command.val);
          socket.emit(command.msgId, { command: command, success: true });
        }
      }
      if (command.type == 'CLICK') {
        var timeoutVal = (data.command.wait) ? data.command.wait : 250;
        var domEle = $(command.css);
        setTimeout(function() {
          $(domEle).click();
        }, timeoutVal);
        socket.emit(command.msgId, { command: command, success: true });
      }
      if (command.type == 'EXISTS') {
        var domEle = $(command.css);
        if (domEle.length < 1) {
          setTimeout(function() {
            var domEle = $(command.css);
            socket.emit(command.msgId, {command: command, details: ((domEle.length > 0) ? true : false)});
          }, 1000);
        } else {
          socket.emit(command.msgId, {command: command, details: true});
        }
      }
      if (command.type == 'TEXT-VAL') {
        var timeoutVal = (data.command.wait) ? data.command.wait : 500;
        var domEle = $(command.css);
        setTimeout(function() {
          var domEle = $(command.css);
          socket.emit(command.msgId, {command: command, details: ((domEle.length > 0) ? $(domEle).text() : '')});
        }, timeoutVal);
      }
    }

    function log(msg) {
      console.log('++++ ' + msg);
    }<commit_msg>Client library update<commit_after>  var retry = 0;
  var socket;
  function connect(url) {
    retry++;
    socket = io.connect( url, { reconnection: false } );
    setTimeout(function() {
      if (!socket.connected) {
        log('Unable to connect (' + retry + ').  Retrying in 10 seconds');
        setTimeout(function() { connect(url) }, 10000);
      } else {
        log('Connected on attempt (' + retry + ')');
        socket.on('disconnect', function() { retry = 0; connect(url) });
        socket.on('bom-do', function (data) {
          console.log('got bom-do message');
          bomDo(data);
        });
      }
    }, 250);
  }
  connect('http://localhost:3033');

  function bomDo(data) {
    console.log('++++ bomDo');
    var command = data.command;
    console.log('++++ command = ' + JSON.stringify(command));
    if (command.type == 'SET-INPUT-VAL') {
      console.log('++++ command.css = ' + command.css);
      var domEle = $(command.css);
      if (!domEle) {
        socket.emit(command.msgId, { command: command, success: false, details: 'No matching elements for ' + command.css });
      } else {
        var currentVal = $(domEle).val();
        // clear out the current contents of the input field
        for (var val_i=0; val_i<currentVal.length; val_i++) {
        console.log('      _ backspacing...');
          $(domEle).sendkeys ('{backspace}');
        }
        console.log('     _ sending ' + command.val);
        $(domEle).sendkeys (command.val);
        socket.emit(command.msgId, { command: command, success: true });
      }
    }
    if (command.type == 'CLICK') {
      var timeoutVal = (data.command.wait) ? data.command.wait : 250;
      var domEle = $(command.css);
      setTimeout(function() {
        $(domEle).click();
      }, timeoutVal);
      socket.emit(command.msgId, { command: command, success: true });
    }
    if (command.type == 'EXISTS') {
      var domEle = $(command.css);
      if (domEle.length < 1) {
        setTimeout(function() {
          var domEle = $(command.css);
          socket.emit(command.msgId, {command: command, details: ((domEle.length > 0) ? true : false)});
        }, 1000);
      } else {
        socket.emit(command.msgId, {command: command, details: true});
      }
    }
    if (command.type == 'TEXT-VAL') {
      var timeoutVal = (data.command.wait) ? data.command.wait : 500;
      var domEle = $(command.css);
      setTimeout(function() {
        var domEle = $(command.css);
        socket.emit(command.msgId, {command: command, details: ((domEle.length > 0) ? $(domEle).text() : '')});
      }, timeoutVal);
    }
  }

  function log(msg) {
    console.log('++++ ' + msg);
  }
<|endoftext|>


<commit_before>var fs        = require("fs");
var async     = require("async");

var webdriver = require("selenium-webdriver");
var PNGDiff   = require("png-diff");
var colors    = require("colors");

var setup     = require(__dirname + "/setup");
var render    = require(__dirname + "/render");

function run(body, done) {

  // Ensure directory structure exists
  setup.directories();
  setup.files();

  // Test Variables
  var cur_build     = body.build || 'build not specified';
  var log_stamp     = 'Time : ' + (new Date).toISOString() + '\nBuild : ' + (cur_build || 'build not specified');
  var capabilities  = { 'browserName' : body.browser };
  var results       = [];
  var waiting       = 0;
  var status        = {'pass_count':0, 'fail_count':0, 'na_count':0, 'error_count':0, 'resolved_count':0, 'total':0}
  var test_started  = false;

  // Retrieve and validate URI list
  try {
    var site_list = require(__dirname + "/sites.json");
    var uri_list  = JSON.parse(JSON.stringify(site_list));
  } catch (e) {
    console.error('\nsites.json is not valid JSON formatting: '.red + e + '\n');
    process.exit(1);
  }

  // Loop through each URI
  async.each(body.urn, function(i, step) {
    collectScreen(i, step);
  });

  // Generate final report only after all screens have been compared
  function renderResults() {
    if (waiting == 0 && test_started == true) {
      console.log("Not waiting!");
      var timestamp = (new Date).toISOString();
      status.total = status.pass_count + status.fail_count + status.na_count + status.error_count;
      //html = render.render(results, timestamp, cur_build, status);

      //fs.writeFileSync("./views/output-" + build + ".html", html);
      //fs.writeFileSync("./views/output.html", html);
      log_stamp += '\nFail : ' + status.fail_count + '\nPass : ' + status.pass_count + '\nError : ' + status.error_count + '\nN/A : ' + status.na_count + '\nResolved : ' + status.resolved_count + '\n-----';
      fs.appendFile('executions.log', log_stamp + '\n', function (err) {
        if (err) console.log('Error appending version to execution log ' + err);
      });

      run_details = [results, timestamp, cur_build, status];
      return done(run_details);
    }
  }

  // Collect and Compare screens
  function collectScreen(urn, step) {

    waiting ++;
    test_started = true;

    var uri         = body.protocol + body.url + urn;
    var uri_no_pro  = body.url + urn;
    var uri_safe    = uri_no_pro.replace(/\//g, "-");

    // Collect Screenshots
    function writeScreenshot(data, name) {
      var filename = name;
      var filepath = __dirname + "/public/assets/images/screenshots/new/";
      fs.writeFileSync(filepath + filename, data, 'base64');
      console.log("\nCapturing latest screens from: \n\t" + uri.green);
    }

    // Spawn Driver(s)
    var driver = new webdriver.Builder().
        withCapabilities(capabilities).
        build();

    driver.manage().window().setSize(parseInt(body.width), parseInt(body.height));

    // Navigate Driver to URL
    driver.get(uri);

    // Compare screenshots
    driver.takeScreenshot().then(function(data, done) {

      writeScreenshot(data, uri_safe + '.png');

      var prev_dir  = __dirname + '/public/assets/images/screenshots/old/';
      var curr_dir  = __dirname + '/public/assets/images/screenshots/new/';
      var diff_dir  = __dirname + '/public/assets/images/screenshots/results/';
      var old_screenshot  = prev_dir + uri_safe + '.png';
      var new_screenshot  = curr_dir + uri_safe + '.png';
      var diff_screenshot = diff_dir + uri_safe + '.png';

      testResult      = {};
      testResult.img1 = '/assets/images/screenshots/old/' + uri_safe + '.png';
      testResult.img2 = '/assets/images/screenshots/new/' + uri_safe + '.png';
      testResult.diff = '/assets/images/screenshots/results/' + uri_safe + '.png';
      testResult.uri  = uri;

      fs.exists(old_screenshot, function(exists) {

        if (exists) {
          PNGDiff.outputDiff(old_screenshot, new_screenshot, diff_screenshot, function(err, diffMetric) {
            if (err) {
              console.log("Result: \n\t" + "Error comparing screenshots ".red + err);
              testResult.result = 'ERROR';
              testResult.explanation = "Error comparing screenshots: \n" + err;
              results.push(testResult);
              status.error_count ++;
              waiting --;
              //renderResults();
            } else {
              console.log('Comparing: \n\t' + old_screenshot.yellow + ' with ' + new_screenshot.yellow);
              if (diffMetric === 1) {
                console.log("Result: \n\t" + "Difference detected.".red + " Saved to " + diff_screenshot + "\n");
                testResult.result = 'FAIL';
                testResult.explanation = "Difference Detected";
                results.push(testResult);
                status.fail_count ++;
                waiting --;
              } else {
                console.log("Result: \n\t" + "No difference.\n".green);
                testResult.result = 'PASS';
                results.push(testResult);
                status.pass_count ++;
                waiting --;
              }
            }
            renderResults();
          });
        } else {
          console.log("\nNo older screen to compare to.".yellow + " Setting this screen to master for the next run\n");
          fs.rename(new_screenshot, old_screenshot, function(err) {
            if (err) console.log("Error moving captured screenshot " + err);
          });
          testResult.result = 'N/A';
          testResult.explanation = "Nothing to compare with. Setting to master for next run.";
          results.push(testResult);
          status.na_count ++;
          renderResults();
          waiting --;
        }
        //waiting --;
        step();
      });
    });
    // Per test teardown - Quit Driver
    driver.quit();
  }
}

module.exports.run = run;
<commit_msg>Remove async loop to use global SE driver<commit_after>var fs        = require("fs");
var async     = require("async");

var webdriver = require("selenium-webdriver");
var PNGDiff   = require("png-diff");
var colors    = require("colors");

var setup     = require(__dirname + "/setup");
var render    = require(__dirname + "/render");

function run(body, done) {

  setup.directories();
  setup.files();

  // Test Variables
  var cur_build     = body.build || 'build not specified';
  var log_stamp     = 'Time : ' + (new Date).toISOString() + '\nBuild : ' + (cur_build || 'build not specified');
  var capabilities  = { 'browserName' : body.browser };
  var results       = [];
  var waiting       = 0;
  var status        = {'pass_count':0, 'fail_count':0, 'na_count':0, 'error_count':0, 'resolved_count':0, 'total':0}
  var test_started  = false;

  // Retrieve and validate URI list
  /*
  try {
    var site_list = require(__dirname + "/sites.json");
    var uri_list  = JSON.parse(JSON.stringify(site_list));
  } catch (e) {
    console.error('\nsites.json is not valid JSON formatting: '.red + e + '\n');
    process.exit(1);
  }
  */

  // Spawn Driver
  var driver = new webdriver.Builder().
      withCapabilities(capabilities).
      build();
  driver.manage().window().setSize(parseInt(body.width), parseInt(body.height));

  // Loop through each URI
  body.urn.forEach( function(i) {
    collectScreen(i);
  });

  // Generate final report only after all screens have been compared
  function renderResults() {
    if (waiting == 0 && test_started == true) {
      driver.quit();
      var timestamp = (new Date).toISOString();
      status.total = status.pass_count + status.fail_count + status.na_count + status.error_count;

      log_stamp += '\nFail : ' + status.fail_count + '\nPass : ' + status.pass_count + '\nError : ' + status.error_count + '\nN/A : ' + status.na_count + '\nResolved : ' + status.resolved_count + '\n-----';
      fs.appendFile('executions.log', log_stamp + '\n', function (err) {
        if (err) console.log('Error appending version to execution log ' + err);
      });

      run_details = [results, timestamp, cur_build, status];
      return done(run_details);
    }
  }

  // Collect and Compare screens
  function collectScreen(urn) {

    waiting ++;
    test_started = true;

    var uri         = body.protocol + body.url + urn;
    var uri_no_pro  = body.url + urn;
    var uri_safe    = uri_no_pro.replace(/\//g, "-");

    // Collect Screenshots
    function writeScreenshot(data, name) {
      var filename = name;
      var filepath = __dirname + "/public/assets/images/screenshots/new/";
      fs.writeFileSync(filepath + filename, data, 'base64');
      console.log("\nCapturing latest screens from: \n\t" + uri.green);
    }

    // Navigate Driver to URL and compare screenshots
    driver.get(uri);
    driver.takeScreenshot().then(function(data, done) {

      writeScreenshot(data, uri_safe + '.png');

      var prev_dir  = __dirname + '/public/assets/images/screenshots/old/';
      var curr_dir  = __dirname + '/public/assets/images/screenshots/new/';
      var diff_dir  = __dirname + '/public/assets/images/screenshots/results/';
      var old_screenshot  = prev_dir + uri_safe + '.png';
      var new_screenshot  = curr_dir + uri_safe + '.png';
      var diff_screenshot = diff_dir + uri_safe + '.png';

      testResult      = {};
      testResult.img1 = '/assets/images/screenshots/old/' + uri_safe + '.png';
      testResult.img2 = '/assets/images/screenshots/new/' + uri_safe + '.png';
      testResult.diff = '/assets/images/screenshots/results/' + uri_safe + '.png';
      testResult.uri  = uri;

      fs.exists(old_screenshot, function(exists) {

        if (exists) {
          PNGDiff.outputDiff(old_screenshot, new_screenshot, diff_screenshot, function(err, diffMetric) {
            if (err) {
              console.log("Result: \n\t" + "Error comparing screenshots ".red + err);
              testResult.result = 'ERROR';
              testResult.explanation = "Error comparing screenshots: \n" + err;
              results.push(testResult);
              status.error_count ++;
              waiting --;
              //renderResults();
            } else {
              console.log('Comparing: \n\t' + old_screenshot.yellow + ' with ' + new_screenshot.yellow);
              if (diffMetric === 1) {
                console.log("Result: \n\t" + "Difference detected.".red + " Saved to " + diff_screenshot + "\n");
                testResult.result = 'FAIL';
                testResult.explanation = "Difference Detected";
                results.push(testResult);
                status.fail_count ++;
                waiting --;
              } else {
                console.log("Result: \n\t" + "No difference.\n".green);
                testResult.result = 'PASS';
                results.push(testResult);
                status.pass_count ++;
                waiting --;
              }
            }
            renderResults();
          });
        } else {
          console.log("\nNo older screen to compare to.".yellow + " Setting this screen to master for the next run\n");
          fs.rename(new_screenshot, old_screenshot, function(err) {
            if (err) console.log("Error moving captured screenshot " + err);
          });
          testResult.result = 'N/A';
          testResult.explanation = "Nothing to compare with. Setting to master for next run.";
          results.push(testResult);
          status.na_count ++;
          waiting --;
          renderResults();
        }
      });
    });
  }
}

module.exports.run = run;
<|endoftext|>