<commit_before>function Game(){
	this.eng = new Engine(vec2(640,480), Utils.get("divGame"));
	this.render = new RaycastRender(this.eng.getData(vec2(480,320)), 60, 420, this);
	this.renderPos = vec2(0,0);

	this.map = null;
	this.fps = Math.floor(1000 / 30);

	this.textures = {};
	this.billboards = {};
	this.keys = [];

	this.lastT = 0;

	this.loadTextures();
}

Game.prototype.getCtx = function(){
	return this.eng.ctx;
};

Game.prototype.getKeyPressed = function(keyCode){
	if (this.keys[keyCode] == 1){
		this.keys[keyCode] = 2;
		return true;
	}

	return false;
};

Game.prototype.loadTextures = function(){
	Colors.ceil = [143,155,77];
	Colors.floor = [115,115,115];

	this.eng.loadKTD("E1M1.ktd", this.textures, Colors.textures, Colors.texturesShadow);
	this.eng.loadKTD("texBillboards.ktd", this.billboards, Colors.billboards, null);
};

Game.prototype.getTexture = function(texId){
	if (texId == 0) return null;

	var ind = this.textures.indexes[texId];
	if (!ind) throw "Invalid Texture Index " + texId + "!";
	if (!this.textures[ind]) throw "Invalid Texture Index " + texId + "!";

	return this.textures[ind];
};

Game.prototype.getBillboard = function(texCode){
	if (!this.billboards[texCode]) throw "Invalid Billboard Code " + texCode + "!";
	return this.billboards[texCode];
};

Game.prototype.newGame = function(deltaT){
	var game = this;
	if (game.textures.indexes && game.billboards.indexes){
		game.map = new MapManager(game);
		game.loopGame(deltaT);
	}else{
		setTimeout(function(){ game.newGame(deltaT); }, game.fps);
	}
};

Game.prototype.loopGame = function(deltaT){
	var game = this;

	var dT = 1 / (deltaT - this.lastT);
	this.lastT = deltaT;

	game.map.loop(dT);
	game.render.draw(game.getCtx(), this.renderPos);

	//setTimeout(function(){ game.loopGame(); }, game.fps);
	requestAnimFrame(function(deltaT){ game.loopGame(deltaT); });
};

Utils.addEvent(window, "load", function(){
	var game = new Game();

	game.newGame();

	Utils.addEvent(document, "keydown", function(e){
		if (window.event) e = window.event;

		if (game.keys[e.keyCode] == 2) return;

		game.keys[e.keyCode] = 1;
	});

	Utils.addEvent(document, "keyup", function(e){
		if (window.event) e = window.event;

		game.keys[e.keyCode] = 0;
	});
});
<commit_msg>Change the resolution of the canvas to adjust the 3D viewport<commit_after>function Game(){
	this.eng = new Engine(vec2(480,320), Utils.get("divGame"));
	this.render = new RaycastRender(this.eng.getData(vec2(480,320)), 60, 420, this);
	this.renderPos = vec2(0,0);

	this.map = null;
	this.fps = Math.floor(1000 / 30);

	this.textures = {};
	this.billboards = {};
	this.keys = [];

	this.lastT = 0;

	this.loadTextures();
}

Game.prototype.getCtx = function(){
	return this.eng.ctx;
};

Game.prototype.getKeyPressed = function(keyCode){
	if (this.keys[keyCode] == 1){
		this.keys[keyCode] = 2;
		return true;
	}

	return false;
};

Game.prototype.loadTextures = function(){
	Colors.ceil = [143,155,77];
	Colors.floor = [115,115,115];

	this.eng.loadKTD("E1M1.ktd", this.textures, Colors.textures, Colors.texturesShadow);
	this.eng.loadKTD("texBillboards.ktd", this.billboards, Colors.billboards, null);
};

Game.prototype.getTexture = function(texId){
	if (texId == 0) return null;

	var ind = this.textures.indexes[texId];
	if (!ind) throw "Invalid Texture Index " + texId + "!";
	if (!this.textures[ind]) throw "Invalid Texture Index " + texId + "!";

	return this.textures[ind];
};

Game.prototype.getBillboard = function(texCode){
	if (!this.billboards[texCode]) throw "Invalid Billboard Code " + texCode + "!";
	return this.billboards[texCode];
};

Game.prototype.newGame = function(deltaT){
	var game = this;
	if (game.textures.indexes && game.billboards.indexes){
		game.map = new MapManager(game);
		game.loopGame(deltaT);
	}else{
		setTimeout(function(){ game.newGame(deltaT); }, game.fps);
	}
};

Game.prototype.loopGame = function(deltaT){
	var game = this;

	var dT = 1 / (deltaT - this.lastT);
	this.lastT = deltaT;

	game.map.loop(dT);
	game.render.draw(game.getCtx(), this.renderPos);

	//setTimeout(function(){ game.loopGame(); }, game.fps);
	requestAnimFrame(function(deltaT){ game.loopGame(deltaT); });
};

Utils.addEvent(window, "load", function(){
	var game = new Game();

	game.newGame();

	Utils.addEvent(document, "keydown", function(e){
		if (window.event) e = window.event;

		if (game.keys[e.keyCode] == 2) return;

		game.keys[e.keyCode] = 1;
	});

	Utils.addEvent(document, "keyup", function(e){
		if (window.event) e = window.event;

		game.keys[e.keyCode] = 0;
	});
});
<|endoftext|>


<commit_before>var webpack = require('webpack');
var path = require('path');
var BannerFooterPlugin = require('banner-footer-webpack-plugin');

module.exports = function(grunt, options) {
  var basePath = 'website-guts/assets/js';
  var expandPath = function(basePath, dir) {
    return grunt.file.expand({cwd: basePath}, dir + '/*.js').reduce(function(map, filepath) {
      map[path.basename(filepath, '.js')] = './' + path.join(basePath, filepath);
      return map;
    }, {});
  };
  var sharedLoaders = [
    { test: /\.hbs$/, loader: 'handlebars-loader' },
    {test: /\.js?$/, exclude: ['bower_components', 'node_modules'], loader: '6to5-loader?experimental&runtime'}
  ];
  var sharedPlugins = [
    new webpack.ProvidePlugin({
      to5Runtime: 'imports?global=>{}!exports?global.to5Runtime!6to5/runtime'
    }),
    new BannerFooterPlugin('<%= grunt.config.get("concat_banner") %>', '<%= grunt.config.get("concat_footer") %>', {
      raw: true
    })
  ];
  function addPlugins(pluginInst) {
    var cloned = sharedPlugins.slice(0);
    cloned.unshift(pluginInst);
    return cloned;
  }

  return {
    options: {
      stats: {
        colors: true,
        modules: true,
        reasons: true
      },
      devtool: 'source-map',
      environment: '<%= grunt.config.get("environment") %>',
      envPlugins: [
        [
          '!dev',
          webpack.optimize.UglifyJsPlugin,
          [{compress: {warnings: false}}]
        ]
      ]
    },
    pages: {
      entry: expandPath(basePath, 'pages'),
      output: {
        path: './dist/assets/js/pages',
        filename: '[name].js',
        sourceMapFilename: '[file].map'
      },
      resolve: {
          extensions: ["", ".js", ".hbs"],
          modulesDirectories: ['node_modules', 'website-guts/templates/client']
      },
      module: {
        loaders: sharedLoaders
      },
      plugins: sharedPlugins
    },
    layouts: {
      entry: expandPath(basePath, 'layouts'),
      output: {
        path: './dist/assets/js/layouts',
        filename: '[name].js',
        sourceMapFilename: '[file].map'
      },
      resolve: {
          extensions: ["", ".js", ".hbs"],
          modulesDirectories: ['node_modules', 'website-guts/templates/client']
      },
      module: {
        loaders: sharedLoaders
      },
      plugins: sharedPlugins
    },
    globalBundle: {
      entry: './website-guts/assets/js/global.js',
      output: {
        path: './dist/assets/js',
        filename: 'bundle.js',
        sourceMapFilename: '[file].map'
      },
      resolve: {
          extensions: ["", ".js", ".hbs"],
          modulesDirectories: ['node_modules', 'bower_components', 'website-guts/templates/client']
      },
      module: {
        loaders: sharedLoaders
      },
      plugins: addPlugins(
        new webpack.ResolverPlugin(
            new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
        )
      )
    }
  }
};
<commit_msg>remove sourcemap filename option<commit_after>var webpack = require('webpack');
var path = require('path');
var BannerFooterPlugin = require('banner-footer-webpack-plugin');

module.exports = function(grunt, options) {
  var basePath = 'website-guts/assets/js';
  var expandPath = function(basePath, dir) {
    return grunt.file.expand({cwd: basePath}, dir + '/*.js').reduce(function(map, filepath) {
      map[path.basename(filepath, '.js')] = './' + path.join(basePath, filepath);
      return map;
    }, {});
  };
  var sharedLoaders = [
    { test: /\.hbs$/, loader: 'handlebars-loader' },
    {test: /\.js?$/, exclude: ['bower_components', 'node_modules'], loader: '6to5-loader?experimental&runtime'}
  ];
  var sharedPlugins = [
    new webpack.ProvidePlugin({
      to5Runtime: 'imports?global=>{}!exports?global.to5Runtime!6to5/runtime'
    }),
    new BannerFooterPlugin('<%= grunt.config.get("concat_banner") %>', '<%= grunt.config.get("concat_footer") %>', {
      raw: true
    })
  ];
  function addPlugins(pluginInst) {
    var cloned = sharedPlugins.slice(0);
    cloned.unshift(pluginInst);
    return cloned;
  }

  return {
    options: {
      stats: {
        colors: true,
        modules: true,
        reasons: true
      },
      devtool: 'source-map',
      environment: '<%= grunt.config.get("environment") %>',
      envPlugins: [
        [
          '!dev',
          webpack.optimize.UglifyJsPlugin,
          [{compress: {warnings: false}}]
        ]
      ]
    },
    pages: {
      entry: expandPath(basePath, 'pages'),
      output: {
        path: './dist/assets/js/pages',
        filename: '[name].js'
      },
      resolve: {
          extensions: ["", ".js", ".hbs"],
          modulesDirectories: ['node_modules', 'website-guts/templates/client']
      },
      module: {
        loaders: sharedLoaders
      },
      plugins: sharedPlugins
    },
    layouts: {
      entry: expandPath(basePath, 'layouts'),
      output: {
        path: './dist/assets/js/layouts',
        filename: '[name].js'
      },
      resolve: {
          extensions: ["", ".js", ".hbs"],
          modulesDirectories: ['node_modules', 'website-guts/templates/client']
      },
      module: {
        loaders: sharedLoaders
      },
      plugins: sharedPlugins
    },
    globalBundle: {
      entry: './website-guts/assets/js/global.js',
      output: {
        path: './dist/assets/js',
        filename: 'bundle.js'
      },
      resolve: {
          extensions: ["", ".js", ".hbs"],
          modulesDirectories: ['node_modules', 'bower_components', 'website-guts/templates/client']
      },
      module: {
        loaders: sharedLoaders
      },
      plugins: addPlugins(
        new webpack.ResolverPlugin(
            new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
        )
      )
    }
  }
};
<|endoftext|>


<commit_before>!function() {
    var ajax_get = function(url, successback, errorback) {
        var xhr;
        if(window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else {
            throw new Error('unsupport XMLHttpRequest');
        }

        if(xhr) {
            xhr.responseType = 'text';
            xhr.timeout = 10000;
            xhr.onreadystatechange = function(e) {
                if(xhr.readyState === 4) {
                    if(xhr.status === 200) {
                        successback(xhr.responseText);
                    } else {
                        errorback(xhr.responseText);
                    }
                }
            }
            xhr.open('get', url, true);
            xhr.send();
        }
    };

    var detectOS = function() {
        var ua = window.navigator.userAgent.toLowerCase();
        if((/iPhone|iPad|iPod/i).test(ua)) {
            return 'ios';
        } else if((/android/i).test(ua)) {
            return 'android';
        }
        return 'other';
    };
    var os = detectOS();
    var vinfo;
    var loadidx = 0;
    var insertJS = function() {
        var version = (vinfo[os] && vinfo[os]['buildVersion']) || vinfo['buildVersion'];
        var j = 0, n, h, s, t, isHashURL;
        if(loadidx < vinfo.moduleList.length) {
            n = vinfo.moduleList[loadidx]['name'];
            h = vinfo.moduleList[loadidx]['hash'];
            t = vinfo.moduleList[loadidx]['type'];
            if(vinfo[os] && vinfo[os]['moduleList']) {
                for(j = 0; j < vinfo[os]['moduleList'].length; j++) {
                    if(vinfo[os]['moduleList'][j]['name'] === n) {
                        h = vinfo[os]['moduleList'][j]['hash'];
                    }
                }
            }
            s = document.createElement('script');
            s.setAttribute('type', 'text/javascript');
            s.setAttribute('charset', 'utf-8');
            s.setAttribute('async', true);
            isHashURL = (/^https?:\/\//i).test(h);
            if(vinfo.cache && !isHashURL) {
                if(hasCache(n, h)) {
                    s.appendChild(document.createTextNode(getCache(n, h)['content']));
                    document.body.appendChild(s);
                    loadedHandler();
                } else {
                    ajax_get([version, n, h].join('/') + '.' + t, function(js) {
                        var n = vinfo.moduleList[loadidx]['name'];
                        var h = vinfo.moduleList[loadidx]['hash'];
                        setCache(n, h, js);
                        s.appendChild(document.createTextNode(js));
                        loadidx += 1;
                        insertJS();
                    }, function(err) {
                        throw new Error('loadm module '  + n + ' failed');
                    });
                    document.body.appendChild(s);
                }
            } else {
                if(!isHashURL) {
                    s.setAttribute('src', [version, n, h].join('/') + '.' + t);
                } else {
                    s.setAttribute('src', h);
                }
                document.body.appendChild(s);
                s.onload = loadedHandler;
            }
        }
    };

    var loadedHandler = function(e) {
        loadidx += 1;
        insertJS();
    };

    var success = function(result) {
        vinfo = JSON.parse(result);
        if(vinfo.cache) {
            setCache('vinfo', new Date().toLocaleString(), JSON.stringify(vinfo));
        } else {
            clearCache();
        }
        insertJS();
    };

    var fail = function(err) {
        if(hasCache('vinfo')) {
            vinfo = JSON.parse(getCache('vinfo')['content']);
            insertJS();
        }
    };

    ajax_get('vinfo.json?rand=' + Math.random().toString().slice(2), success, fail);

    var hasCache = function(modname, modversion) {
        if(window.localStorage && typeof modname === 'string') {
            var mod = window.localStorage.getItem('paiband_cache_' + modname);
            if(mod && modversion) {
                mod = JSON.parse(mod);
                return mod['version'] === modversion;
            } else {
                return !!mod;
            }
        }
        return false;
    };

    var setCache = function(modname, modversion, modcontent) {
        if(window.localStorage && typeof modname === 'string' && typeof modversion === 'string' && typeof modcontent === 'string') {
            try {
                window.localStorage.setItem('paiband_cache_' + modname, JSON.stringify({
                    version: modversion,
                    content: modcontent
                }))
            } catch(e) {
            }
        }
    };

    var getCache = function(modname, modversion) {
        if(window.localStorage && typeof modname === 'string') {
            var mod = window.localStorage.getItem('paiband_cache_' + modname);
            if(mod) {
                mod = JSON.parse(mod);
                if(modversion) {
                    if(mod['version'] === modversion) {
                        return mod;
                    }
                } else {
                    return mod;
                }
            }
        }
        return null;
    };

    var removeCache = function(modname, modversion) {
        if(window.localStorage) {
            if(hasCache(modname, modversion)) {
                try {
                    window.localStorage.removeItem(modname);
                } catch(e) {
                }
            }
        }
    };

    var clearCache = function() {
        if(window.localStorage) {
            var len = window.localStorage.length;
            var i = 0, key;
            for(var i = 0; i < len; i++) {
                key = window.localStorage.key(i);
                if(key.indexOf('paiband_cache_') !== -1) {
                    removeCache(key);
                }
            }
        }
    }
}();
<commit_msg>update bz.js<commit_after>!function() {
    var ajax_get = function(url, successback, errorback) {
        var xhr;
        if(window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else {
            throw new Error('unsupport XMLHttpRequest');
        }

        if(xhr) {
            xhr.responseType = 'text';
            xhr.timeout = 10000;
            xhr.onreadystatechange = function(e) {
                if(xhr.readyState === 4) {
                    if(xhr.status === 200) {
                        successback(xhr.responseText);
                    } else {
                        errorback(xhr.responseText);
                    }
                }
            }
            xhr.open('get', url, true);
            xhr.send();
        }
    };

    var detectOS = function() {
        var ua = window.navigator.userAgent.toLowerCase();
        if((/iPhone|iPad|iPod/i).test(ua)) {
            return 'ios';
        } else if((/android/i).test(ua)) {
            return 'android';
        }
        return 'other';
    };
    var os = detectOS();
    var vinfo;
    var insertJS = function(index) {
        var version = (vinfo[os] && vinfo[os]['buildVersion']) || vinfo['buildVersion'];
        var j = 0, n, h, t, m, s, isHashURL;
        if(index < vinfo.moduleList.length) {
            m = vinfo.moduleList[index];
            n = m['name'];
            h = m['hash'];
            t = m['type'];
            if(vinfo[os] && vinfo[os]['moduleList']) {
                for(j = 0; j < vinfo[os]['moduleList'].length; j++) {
                    if(vinfo[os]['moduleList'][j]['name'] === n) {
                        h = vinfo[os]['moduleList'][j]['hash'];
                    }
                }
            }
            isHashURL = (/^https?:\/\//i).test(h);
            if(vinfo.cache && !isHashURL) {
                loadModule(index, n, h, t);
            } else {
                s = document.createElement('script');
                s.setAttribute('type', 'text/javascript');
                s.setAttribute('charset', 'utf-8');
                if(!isHashURL) {
                    s.setAttribute('src', [version, n, h].join('/') + '.' + t);
                } else {
                    s.setAttribute('src', h);
                }
                document.body.appendChild(s);
            }
        }
    };

    var loadModule = function(index, n, h, t) {
        var version = (vinfo[os] && vinfo[os]['buildVersion']) || vinfo['buildVersion'];
        var j = 0, m, isHashURL;
        if(index < vinfo.moduleList.length) {
            m = vinfo.moduleList[index];
            if(hasCache(n, h)) {
                m.content = getCache(n, h)['content'];
                m.done = true;
                if(checkModuleAllLoaded()) {
                    executeModuleLoaded();
                }
            } else {
                ajax_get([version, n, h].join('/') + '.' + t, function(js) {
                    m.content = js;
                    m.done = true;
                    setCache(n, h, js);
                    if(checkModuleAllLoaded()) {
                        executeModuleLoaded();
                    }
                }, function(err) {
                    throw new Error('loadm module '  + n + ' failed');
                });
            }
        }
    };

    var checkModuleAllLoaded = function() {
        for(var i = 0; i < vinfo.moduleList.length; i++) {
            if(!vinfo.moduleList[i].done) {
                return false;
            }
        }
        return true;
    };

    var executeModuleLoaded = function() {
        console.log(vinfo);
        var s, i;
        for(i = 0; i < vinfo.moduleList.length; i++) {
            s = document.createElement('script');
            s.setAttribute('type', 'text/javascript');
            s.setAttribute('charset', 'utf-8');
            s.appendChild(document.createTextNode(vinfo['moduleList'][i]['content']));
            document.body.appendChild(s);
        }
    };

    var success = function(result) {
        vinfo = JSON.parse(result);
        if(vinfo.cache) {
            setCache('vinfo', new Date().toLocaleString(), JSON.stringify(vinfo));
        } else {
            clearCache();
        }
        if(vinfo.moduleList && vinfo.moduleList.length) {
            for(var i = 0; i < vinfo.moduleList.length; i++) {
                insertJS(i);
            }
        }
    };

    var fail = function(err) {
        if(hasCache('vinfo')) {
            vinfo = JSON.parse(getCache('vinfo')['content']);
            insertJS();
        }
    };

    ajax_get('vinfo.json?rand=' + Math.random().toString().slice(2), success, fail);

    var hasCache = function(modname, modversion) {
        if(window.localStorage && typeof modname === 'string') {
            var mod = window.localStorage.getItem('paiband_cache_' + modname);
            if(mod && modversion) {
                mod = JSON.parse(mod);
                return mod['version'] === modversion;
            } else {
                return !!mod;
            }
        }
        return false;
    };

    var setCache = function(modname, modversion, modcontent) {
        if(window.localStorage && typeof modname === 'string' && typeof modversion === 'string' && typeof modcontent === 'string') {
            try {
                window.localStorage.setItem('paiband_cache_' + modname, JSON.stringify({
                    version: modversion,
                    content: modcontent
                }))
            } catch(e) {
            }
        }
    };

    var getCache = function(modname, modversion) {
        if(window.localStorage && typeof modname === 'string') {
            var mod = window.localStorage.getItem('paiband_cache_' + modname);
            if(mod) {
                mod = JSON.parse(mod);
                if(modversion) {
                    if(mod['version'] === modversion) {
                        return mod;
                    }
                } else {
                    return mod;
                }
            }
        }
        return null;
    };

    var removeCache = function(modname, modversion) {
        if(window.localStorage) {
            if(hasCache(modname, modversion)) {
                try {
                    window.localStorage.removeItem(modname);
                } catch(e) {
                }
            }
        }
    };

    var clearCache = function() {
        if(window.localStorage) {
            var len = window.localStorage.length;
            var i = 0, key;
            for(var i = 0; i < len; i++) {
                key = window.localStorage.key(i);
                if(key.indexOf('paiband_cache_') !== -1) {
                    removeCache(key);
                }
            }
        }
    }
}();
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var path = require('path');
var karma = require('karma');

function normalizeOptions(options) {
	var codeGlobs = ['src/**/*.js', '!src/**/*.soy.js', 'test/**/*.js', 'gulpfile.js'];

	options = options || {};
	options.buildAmdDest = options.buildAmdDest || 'build/amd';
	options.buildGlobalsJqueryDest = options.buildGlobalsJqueryDest || 'build/globals-jquery';
	options.buildAmdJqueryDest = options.buildAmdJqueryDest || 'build/amd-jquery';
	options.buildJqueryDest = options.buildJqueryDest || 'build/jquery';
	options.bundleCssFileName = options.bundleCssFileName || 'all.css';
	options.bundleFileName = options.bundleFileName || 'metal.js';
	options.buildDest = options.buildDest || 'build/globals';
	options.buildSrc = options.buildSrc || 'src/**/*.js';
	options.cleanDir = options.cleanDir || 'build';
	options.cssDest = options.cssDest || 'build';
	options.cssSrc = options.cssSrc || 'src/**/*.css';
	options.formatGlobs = options.formatGlobs || codeGlobs;
	options.globalName = options.globalName || 'metal';
	options.gulp = options.gulp || gulp;
	options.jsDocConfFile = options.jsDocConfFile || path.resolve(__dirname, '../jsdoc.json');
	options.karma = options.karma || karma;
	options.lintGlobs = options.lintGlobs || codeGlobs;
	options.uglifySrc = options.uglifySrc || 'build/**/*.js';
	options.moduleName = options.moduleName || 'metal';
	options.noSoy = options.noSoy || false;
	options.scssIncludePaths = options.scssIncludePaths || ['node_modules'];
	options.scssSrc = options.scssSrc || 'src/**/*.scss';
	options.soyDest = options.soyDest || 'src';
	options.soyDeps = options.soyDeps || 'node_modules/metal*/src/**/*.soy';
	options.soyLocales = options.soyLocales;
	options.soyMessageFilePathFormat = options.soyMessageFilePathFormat;
	options.soySrc = options.soySrc || 'src/**/*.soy';
	options.taskPrefix = options.taskPrefix || '';
	options.mainBuildJsTasks = options.mainBuildJsTasks || [options.taskPrefix + 'build:globals:js'];
	options.testBrowsers = options.testBrowsers || ['Chrome', 'Firefox', 'Safari', 'IE9 - Win7', 'IE10 - Win7', 'IE11 - Win7'];
	options.testNodeSrc = options.testNodeSrc || 'test/**/*.js';
	options.testSaucelabsBrowsers = options.testSaucelabsBrowsers || {
		sl_chrome: {
			base: 'SauceLabs',
			browserName: 'chrome'
		},
		sl_safari: {
			base: 'SauceLabs',
			browserName: 'safari'
		},
		sl_firefox: {
			base: 'SauceLabs',
			browserName: 'firefox'
		},
		sl_ie_9: {
			base: 'SauceLabs',
			browserName: 'internet explorer',
			platform: 'Windows 7',
			version: '9'
		},
		sl_ie_10: {
			base: 'SauceLabs',
			browserName: 'internet explorer',
			platform: 'Windows 7',
			version: '10'
		},
		sl_ie_11: {
			base: 'SauceLabs',
			browserName: 'internet explorer',
			platform: 'Windows 8.1',
			version: '11'
		},
		sl_edge_13: {
			base: 'SauceLabs',
			browserName: 'microsoftedge',
			platform: 'Windows 10',
			version: '13'
		},
		sl_iphone: {
			base: 'SauceLabs',
			browserName: 'iphone',
			platform: 'OS X 10.10',
			version: '7.1'
		},
		sl_android_4: {
			base: 'SauceLabs',
			browserName: 'android',
			platform: 'Linux',
			version: '4.4'
		},
		sl_android_5: {
			base: 'SauceLabs',
			browserName: 'android',
			platform: 'Linux',
			version: '5.0'
		}
	};

	return options;
}

module.exports = normalizeOptions;
<commit_msg>Updates iOS Saucelabs configuration<commit_after>'use strict';

var gulp = require('gulp');
var path = require('path');
var karma = require('karma');

function normalizeOptions(options) {
	var codeGlobs = ['src/**/*.js', '!src/**/*.soy.js', 'test/**/*.js', 'gulpfile.js'];

	options = options || {};
	options.buildAmdDest = options.buildAmdDest || 'build/amd';
	options.buildGlobalsJqueryDest = options.buildGlobalsJqueryDest || 'build/globals-jquery';
	options.buildAmdJqueryDest = options.buildAmdJqueryDest || 'build/amd-jquery';
	options.buildJqueryDest = options.buildJqueryDest || 'build/jquery';
	options.bundleCssFileName = options.bundleCssFileName || 'all.css';
	options.bundleFileName = options.bundleFileName || 'metal.js';
	options.buildDest = options.buildDest || 'build/globals';
	options.buildSrc = options.buildSrc || 'src/**/*.js';
	options.cleanDir = options.cleanDir || 'build';
	options.cssDest = options.cssDest || 'build';
	options.cssSrc = options.cssSrc || 'src/**/*.css';
	options.formatGlobs = options.formatGlobs || codeGlobs;
	options.globalName = options.globalName || 'metal';
	options.gulp = options.gulp || gulp;
	options.jsDocConfFile = options.jsDocConfFile || path.resolve(__dirname, '../jsdoc.json');
	options.karma = options.karma || karma;
	options.lintGlobs = options.lintGlobs || codeGlobs;
	options.uglifySrc = options.uglifySrc || 'build/**/*.js';
	options.moduleName = options.moduleName || 'metal';
	options.noSoy = options.noSoy || false;
	options.scssIncludePaths = options.scssIncludePaths || ['node_modules'];
	options.scssSrc = options.scssSrc || 'src/**/*.scss';
	options.soyDest = options.soyDest || 'src';
	options.soyDeps = options.soyDeps || 'node_modules/metal*/src/**/*.soy';
	options.soyLocales = options.soyLocales;
	options.soyMessageFilePathFormat = options.soyMessageFilePathFormat;
	options.soySrc = options.soySrc || 'src/**/*.soy';
	options.taskPrefix = options.taskPrefix || '';
	options.mainBuildJsTasks = options.mainBuildJsTasks || [options.taskPrefix + 'build:globals:js'];
	options.testBrowsers = options.testBrowsers || ['Chrome', 'Firefox', 'Safari', 'IE9 - Win7', 'IE10 - Win7', 'IE11 - Win7'];
	options.testNodeSrc = options.testNodeSrc || 'test/**/*.js';
	options.testSaucelabsBrowsers = options.testSaucelabsBrowsers || {
		sl_chrome: {
			base: 'SauceLabs',
			browserName: 'chrome'
		},
		sl_safari: {
			base: 'SauceLabs',
			browserName: 'safari'
		},
		sl_firefox: {
			base: 'SauceLabs',
			browserName: 'firefox'
		},
		sl_ie_9: {
			base: 'SauceLabs',
			browserName: 'internet explorer',
			platform: 'Windows 7',
			version: '9'
		},
		sl_ie_10: {
			base: 'SauceLabs',
			browserName: 'internet explorer',
			platform: 'Windows 7',
			version: '10'
		},
		sl_ie_11: {
			base: 'SauceLabs',
			browserName: 'internet explorer',
			platform: 'Windows 8.1',
			version: '11'
		},
		sl_edge_13: {
			base: 'SauceLabs',
			browserName: 'microsoftedge',
			platform: 'Windows 10',
			version: '13'
		},
		sl_iphone: {
			appiumVersion: '1.6.0',
			base: 'SauceLabs',
			browserName: 'Safari',
			deviceName: "iPhone 6 Simulator",
			deviceOrientation: "portrait",
			platformName: 'iOS',
			platformVersion: '9.3'
		},
		sl_android_4: {
			base: 'SauceLabs',
			browserName: 'android',
			platform: 'Linux',
			version: '4.4'
		},
		sl_android_5: {
			base: 'SauceLabs',
			browserName: 'android',
			platform: 'Linux',
			version: '5.0'
		}
	};

	return options;
}

module.exports = normalizeOptions;
<|endoftext|>


<commit_before>import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import { hashHistory } from 'react-router';
import { routerMiddleware } from 'react-router-redux';
import rootReducer from '../reducers';

const logger = createLogger({
  level: 'info',
  collapsed: true,
});

const router = routerMiddleware(hashHistory);

const enhancer = compose(
  applyMiddleware(thunk, router, logger),
  window.devToolsExtension ? window.devToolsExtension() : noop => noop
);

export default function configureStore(initialState) {
  const store = createStore(rootReducer, initialState, enhancer);

  if (module.hot) {
    module.hot.accept('../reducers', () =>
      store.replaceReducer(require('../reducers')) // eslint-disable-line global-require
    );
  }

  return store;
}
<commit_msg>Add actionCreators option for window.devToolsExtension()<commit_after>import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import { hashHistory } from 'react-router';
import { routerMiddleware, push } from 'react-router-redux';
import rootReducer from '../reducers';

import * as counterActions from '../actions/counter';

const actionCreators = {
  ...counterActions,
  push,
};

const logger = createLogger({
  level: 'info',
  collapsed: true,
});

const router = routerMiddleware(hashHistory);

const enhancer = compose(
  applyMiddleware(thunk, router, logger),
  window.devToolsExtension ?
    window.devToolsExtension({ actionCreators }) :
    noop => noop
);

export default function configureStore(initialState) {
  const store = createStore(rootReducer, initialState, enhancer);

  if (module.hot) {
    module.hot.accept('../reducers', () =>
      store.replaceReducer(require('../reducers')) // eslint-disable-line global-require
    );
  }

  return store;
}
<|endoftext|>


<commit_before>'use strict';

// FUNCTIONS //

var expm1 = Math.expm1 || function(x) {
	return Math.exp(x) - 1;
};
var pow = Math.pow;

// PARTIAL //

/**
* FUNCTION: partial( lambda, k )
*	Partially applies shape parameter `lambda` and scale parameter `k` and returns a function for evaluating the cumulative distribution function (CDF) for a Weibull distribution.
*
* @param {Number} lambda - shape parameter
* @param {Number} k - scale parameter
* @returns {Function} CDF
*/
function partial( lambda, k ) {

	/**
	* FUNCTION: cdf( x )
	*	Evaluates the cumulative distribution function (CDF) for a Weibull distribution.
	*
	* @private
	* @param {Number} x - input value
	* @returns {Number} evaluated CDF
	*/
	return function cdf( x ) {
		if ( x < 0 ) {
			return 0;
		}
		return -expm1( - pow( x / lambda, k ) );
	};
} // end FUNCTION partial()

// EXPORTS //

module.exports = partial;
<commit_msg>Update partial.js<commit_after>'use strict';

// FUNCTIONS //

var expm1 = Math.expm1;
var pow = Math.pow;

// PARTIAL //

/**
* FUNCTION: partial( lambda, k )
*	Partially applies shape parameter `lambda` and scale parameter `k` and returns a function for evaluating the cumulative distribution function (CDF) for a Weibull distribution.
*
* @param {Number} lambda - shape parameter
* @param {Number} k - scale parameter
* @returns {Function} CDF
*/
function partial( lambda, k ) {

	/**
	* FUNCTION: cdf( x )
	*	Evaluates the cumulative distribution function (CDF) for a Weibull distribution.
	*
	* @private
	* @param {Number} x - input value
	* @returns {Number} evaluated CDF
	*/
	return function cdf( x ) {
		if ( x < 0 ) {
			return 0;
		}
		return -expm1( - pow( x / lambda, k ) );
	};
} // end FUNCTION partial()

// EXPORTS //

module.exports = partial;
<|endoftext|>


<commit_before>"use strict";

var fs = require('fs');
var gm = require('gm');
var pdf = require('pdfinfo');
var path = require('path');
var async = require('async');

var options = {
    type: 'png',
    size: 1024,
    density: 600,
    outputdir: null,
    targetname: 'test_'
};

var Pdf2Img = function () {
};

Pdf2Img.prototype.setOptions = function (opts) {
    options.type = opts.type || options.type;
    options.size = opts.size || options.size;
    options.density = opts.density || options.density;
    options.outputdir = opts.outputdir || options.outputdir;
    options.targetname = opts.targetname || options.targetname;
};

Pdf2Img.prototype.convert = function (file, callbackreturn) {
    async.waterfall([
        function (callback) {
            fs.stat(file, function (error, result) {
                if (error) callback('[Error: File not found]', null);
                else {
                    if (!fs.existsSync(options.outputdir)) {
                        fs.mkdirSync(options.outputdir);
                    }
                    var input = fs.createReadStream(file);
                    callback(null, input);
                }
            });
        },

        function (input, callback) {
            pdf(input).info(function (error, data) {
                if (error) callback(error, null);
                else callback(null, data);
            });
        },

        function (data, callback) {
            var pages = [];
            if (data.pages === 0 || data.pages === '0')
                callback('[Error: Invalid page number]', null);

            for (var i = 1; i <= data.pages; i++) {
                pages.push(i);

                if (i === data.pages) callback(null, pages);
            }
        },

        function (pages, callback) {
            async.map(pages, function (page, callbackmap) {
                var inputStream = fs.createReadStream(file);
                var outputStream = fs.createWriteStream(options.outputdir + '/' + options.targetname + page + '.' + options.type);
                convertPdf2Img(inputStream, outputStream, page, function (error, result) {
                    if (!error) {
                        result.page = page;
                    }

                    callbackmap(error, result);
                });
            }, callback);
        }
    ], callbackreturn);
};

var convertPdf2Img = function (input, output, page, callback) {
    var datasize = 0;

    if (input.path) {
        var filepath = input.path;
    } else {
        callback('[Error: Invalid file path]', null);
    }

    var filename = filepath + '[' + (page - 1) + ']';

    var result = gm(input, filename)
        .density(options.density, options.density)
        .resize(options.size)
        .stream(options.type);

    output.on('error', function (error) {
        callback(error, null);
    });

    result.on('error', function (error) {
        callback(error, null);
    });

    result.on('data', function (data) {
        datasize = data.length;
    });

    result.on('end', function () {
        if (datasize < 127) {
            return callback('[Error: Invalid data size]', null);
        }

        var results = {
            page: 0,
            name: path.basename(output.path),
            path: output.path
        };

        output.end();
        callback(null, results);
    });

    result.pipe(output);
};

module.exports = new Pdf2Img;<commit_msg>Datasize below magic number should not throw error<commit_after>"use strict";

var fs = require('fs');
var gm = require('gm');
var pdf = require('pdfinfo');
var path = require('path');
var async = require('async');

var options = {
    type: 'png',
    size: 1024,
    density: 600,
    outputdir: null,
    targetname: 'test_'
};

var Pdf2Img = function () {
};

Pdf2Img.prototype.setOptions = function (opts) {
    options.type = opts.type || options.type;
    options.size = opts.size || options.size;
    options.density = opts.density || options.density;
    options.outputdir = opts.outputdir || options.outputdir;
    options.targetname = opts.targetname || options.targetname;
};

Pdf2Img.prototype.convert = function (file, callbackreturn) {
    async.waterfall([
        function (callback) {
            fs.stat(file, function (error, result) {
                if (error) callback('[Error: File not found]', null);
                else {
                    if (!fs.existsSync(options.outputdir)) {
                        fs.mkdirSync(options.outputdir);
                    }
                    var input = fs.createReadStream(file);
                    callback(null, input);
                }
            });
        },

        function (input, callback) {
            pdf(input).info(function (error, data) {
                if (error) callback(error, null);
                else callback(null, data);
            });
        },

        function (data, callback) {
            var pages = [];
            if (data.pages === 0 || data.pages === '0')
                callback('[Error: Invalid page number]', null);

            for (var i = 1; i <= data.pages; i++) {
                pages.push(i);

                if (i === data.pages) callback(null, pages);
            }
        },

        function (pages, callback) {
            async.map(pages, function (page, callbackmap) {
                var inputStream = fs.createReadStream(file);
                var outputStream = fs.createWriteStream(options.outputdir + '/' + options.targetname + page + '.' + options.type);
                convertPdf2Img(inputStream, outputStream, page, function (error, result) {
                    if (!error) {
                        result.page = page;
                    }

                    callbackmap(error, result);
                });
            }, callback);
        }
    ], callbackreturn);
};

var convertPdf2Img = function (input, output, page, callback) {
    var datasize = 0;

    if (input.path) {
        var filepath = input.path;
    } else {
        callback('[Error: Invalid file path]', null);
    }

    var filename = filepath + '[' + (page - 1) + ']';

    var result = gm(input, filename)
        .density(options.density, options.density)
        .resize(options.size)
        .stream(options.type);

    output.on('error', function (error) {
        callback(error, null);
    });

    result.on('error', function (error) {
        callback(error, null);
    });

    result.on('data', function (data) {
        datasize = data.length;
    });

    result.on('end', function () {
        if (datasize < 127) {
            console.log('Datasize below magic number');
            console.log('Path', output.path);
        }

        var results = {
            page: 0,
            name: path.basename(output.path),
            path: output.path
        };

        output.end();
        callback(null, results);
    });

    result.pipe(output);
};

module.exports = new Pdf2Img;<|endoftext|>


<commit_before>(function(factory){

	'use strict';

	if (typeof module === 'object' && module.exports) {
		module.exports = factory( require('axios') );
	} else {
		factory(axios);
	}

})(function PersonaFactory(axios){

	'use strict';

	function Persona(data){

		var self = this;

		this.dataValues = data || {}

		function get(key){
			if (key === undefined) {
				return self.dataValues;
			}
			return self.dataValues[key];
		}

		this.get = get;

	}

	Persona.find = function find(code){
		return axios.get('https://soa.afip.gob.ar/sr-padron/v2/persona/' + code).then(function(response){

			var json = response.data;
			if (!json.success) { return null; }
			var data = json.data;

			var address = (function(data){
				return data.direccion + ', ' + (data.localidad||'') + ', Argentina';
			})(data.domicilioFiscal);

			return new Persona(Object.assign(data, {
				name : data.nombre,
				type : data.tipoPersona,
				address : address
			}));

		});
	}

	return Persona;

});<commit_msg>better address<commit_after>(function(factory){

	'use strict';

	if (typeof module === 'object' && module.exports) {
		module.exports = factory( require('axios') );
	} else {
		factory(axios);
	}

})(function PersonaFactory(axios){

	'use strict';

	function Persona(data){

		var self = this;

		this.dataValues = data || {}

		function get(key){
			if (key === undefined) {
				return self.dataValues;
			}
			return self.dataValues[key];
		}

		this.get = get;

	}

	Persona.find = function find(code){
		return axios.get('https://soa.afip.gob.ar/sr-padron/v2/persona/' + code).then(function(response){

			var json = response.data;
			if (!json.success) { return null; }
			var data = json.data;

			var address = (function(data){
				var a = null;
				if (data) {
					if (data.direccion) {
						a = data.direccion;
					}
					if (a && data.localidad) {
						a += ', ' + data.localidad;
					}
				}
				return a;
			})(data.domicilioFiscal);

			return new Persona(Object.assign(data, {
				name : data.nombre,
				type : data.tipoPersona,
				address : address
			}));

		});
	}

	return Persona;

});<|endoftext|>


<commit_before>var fs = require('fs'),
    sys = require('sys'),
    path = require('path'),
    events = require('events'),
    run = require('run'),
    jsontemplate = require('json-template'),
    child_process = require('child_process'),
    markdown = require('markdown');

exports.readFile = function(filename, callback){
    fs.readFile(filename, function(err, data){
        if(err) return callback(err, null);
        var ext = path.extname(filename);
        if(ext == '.md'){
            var dialect = markdown.Markdown.dialects.Maruku;
            var jsonml = markdown.parse(data, dialect);
            var result = {};
            if(jsonml.length > 1 && !(jsonml[1] instanceof Array)){
                result = jsonml[1];
            }
            result.body = markdown.toHTML(jsonml);
            result.filename = path.basename(filename);
            callback(null, result);
        }
        else {
            callback(new Error('Unknown format: ' + ext), null);
        }
    });
};

exports.readData = function(dirname, callback){
    fs.readdir(dirname, function(err, files){
        if(err) return callback(err, null);
        if(!files.length) return callback(null, []);
        var data = [];
        var waiting = files.length;
        files.forEach(function(file){
            exports.readFile(path.join(dirname, file), function(err, fileData){
                if(err) callback(err, null);
                data.push(fileData);
                waiting -= 1;
                if(!waiting){
                    callback(null, data);
                }
            });
        });
    });
};

exports.loadViews = function(dirname, callback){
    fs.readdir(dirname, function(err, files){
        if(err) return callback(err, null);
        if(!files.length) return callback(null, {});
        callback(null, files.reduce(function(a,x){
            var basename = path.basename(x);
            if(/\.js$/.exec(basename)){
                var module_name = basename.replace(/\.js$/,'');
                a[module_name] = require(path.join(dirname, module_name));
            }
            return a;
        }, {}));
    });
};

exports.runViews = function(opts, callback){
    var partials = {};
    var tasks = Object.keys(opts.views).reduce(function(a,k){
        var view = opts.views[k];
        a[k] = run.requires(view.requires, function(task){
            var viewEnv = {
                emit: function(path, data){
                    exports.emit(opts.output_dir, path, data, function(err){
                        if(err) throw err;
                    });
                },
                done: task.done
            };
            view.parse(viewEnv, opts.templates, opts.data, partials);
        });
        return a;
    }, {});
    run.auto(tasks, callback);
};

exports.emit = function(output_dir, urlpath, data, callback){
    var filename = output_dir + '/' + urlpath.replace(/^\//, '');
    var dirname = path.dirname(filename);
    path.exists(dirname, function(exists){
        if(!exists){
            child_process.exec('mkdir -p ' + dirname, function(err){
                fs.writeFile(filename, data, callback);
            });
        }
        else {
            fs.writeFile(filename, data, callback);
        }
    });
};

exports.loadTemplates = function(template_dir, callback){
    fs.readdir(template_dir, function(err, files){
        if(err) return callback(err, null);
        if(!files.length) return callback(null, {});
        var templates = {};
        var waiting = files.length;
        files.forEach(function(file){
            fs.readFile(path.join(template_dir, file), function(err, data){
                if(err) callback(err, null);
                var cache;
                templates.__defineGetter__(file, function(){
                    cache = cache || new jsontemplate.Template(data);
                    return cache;
                });
                waiting -= 1;
                if(!waiting){
                    callback(null, templates);
                }
            });
        });
    });
};

exports.run = function(opt, callback){
    run.auto({
        templates: function(task){
            exports.loadTemplates(opt.template_dir, function(err, templates){
                opt.templates = templates;
                task.done();
            });
        },
        views: function(task){
            exports.loadViews(opt.view_dir, function(err, views){
                opt.views = views;
                task.done();
            });
        },
        data: function(task){
            exports.readData(opt.data_dir, function(err, data){
                opt.data = data;
                task.done();
            });
        },
        removedir: function(task){
            child_process.exec('rm -r ' + opt.output_dir, function(err){
                task.done();
            });
        },
        mkdir: run.requires(['removedir'], function(task){
            child_process.exec('mkdir ' + opt.output_dir, function(err){
                task.done();
            });
       })
    }, function(){
        exports.runViews(opt, callback);
    });
};
<commit_msg>ignore data when readFile returns error<commit_after>var fs = require('fs'),
    sys = require('sys'),
    path = require('path'),
    events = require('events'),
    run = require('run'),
    jsontemplate = require('json-template'),
    child_process = require('child_process'),
    markdown = require('markdown');

exports.readFile = function(filename, callback){
    fs.readFile(filename, function(err, data){
        if(err) return callback(err, null);
        var ext = path.extname(filename);
        if(ext == '.md'){
            var dialect = markdown.Markdown.dialects.Maruku;
            var jsonml = markdown.parse(data, dialect);
            var result = {};
            if(jsonml.length > 1 && !(jsonml[1] instanceof Array)){
                result = jsonml[1];
            }
            result.body = markdown.toHTML(jsonml);
            result.filename = path.basename(filename);
            callback(null, result);
        }
        else {
            callback(new Error('Unknown format: ' + ext), null);
        }
    });
};

exports.readData = function(dirname, callback){
    fs.readdir(dirname, function(err, files){
        if(err) return callback(err, null);
        if(!files.length) return callback(null, []);
        var data = [];
        var waiting = files.length;
        files.forEach(function(file){
            exports.readFile(path.join(dirname, file), function(err, fileData){
                // ignore errors
                if(!err){
                    data.push(fileData);
                }
                waiting -= 1;
                if(!waiting){
                    callback(null, data);
                }
            });
        });
    });
};

exports.loadViews = function(dirname, callback){
    fs.readdir(dirname, function(err, files){
        if(err) return callback(err, null);
        if(!files.length) return callback(null, {});
        callback(null, files.reduce(function(a,x){
            var basename = path.basename(x);
            if(/\.js$/.exec(basename)){
                var module_name = basename.replace(/\.js$/,'');
                a[module_name] = require(path.join(dirname, module_name));
            }
            return a;
        }, {}));
    });
};

exports.runViews = function(opts, callback){
    var partials = {};
    var tasks = Object.keys(opts.views).reduce(function(a,k){
        var view = opts.views[k];
        a[k] = run.requires(view.requires, function(task){
            var viewEnv = {
                emit: function(path, data){
                    exports.emit(opts.output_dir, path, data, function(err){
                        if(err) throw err;
                    });
                },
                done: task.done
            };
            view.parse(viewEnv, opts.templates, opts.data, partials);
        });
        return a;
    }, {});
    run.auto(tasks, callback);
};

exports.emit = function(output_dir, urlpath, data, callback){
    var filename = output_dir + '/' + urlpath.replace(/^\//, '');
    var dirname = path.dirname(filename);
    path.exists(dirname, function(exists){
        if(!exists){
            child_process.exec('mkdir -p ' + dirname, function(err){
                fs.writeFile(filename, data, callback);
            });
        }
        else {
            fs.writeFile(filename, data, callback);
        }
    });
};

exports.loadTemplates = function(template_dir, callback){
    fs.readdir(template_dir, function(err, files){
        if(err) return callback(err, null);
        if(!files.length) return callback(null, {});
        var templates = {};
        var waiting = files.length;
        files.forEach(function(file){
            fs.readFile(path.join(template_dir, file), function(err, data){
                if(err) callback(err, null);
                var cache;
                templates.__defineGetter__(file, function(){
                    cache = cache || new jsontemplate.Template(data);
                    return cache;
                });
                waiting -= 1;
                if(!waiting){
                    callback(null, templates);
                }
            });
        });
    });
};

exports.run = function(opt, callback){
    run.auto({
        templates: function(task){
            exports.loadTemplates(opt.template_dir, function(err, templates){
                opt.templates = templates;
                task.done();
            });
        },
        views: function(task){
            exports.loadViews(opt.view_dir, function(err, views){
                opt.views = views;
                task.done();
            });
        },
        data: function(task){
            exports.readData(opt.data_dir, function(err, data){
                opt.data = data;
                task.done();
            });
        },
        removedir: function(task){
            child_process.exec('rm -r ' + opt.output_dir, function(err){
                task.done();
            });
        },
        mkdir: run.requires(['removedir'], function(task){
            child_process.exec('mkdir ' + opt.output_dir, function(err){
                task.done();
            });
       })
    }, function(){
        exports.runViews(opt, callback);
    });
};
<|endoftext|>


<commit_before>'use strict';

var async   = require('async');

var logger  = require('./logger');

var SATOSHI_FACTOR = 1e8;
var SESSION_TIMEOUT = 60 * 60 * 1000;
var POLLING_RATE = 60 * 1000; // poll each minute

var db = null;

var tickerPlugin = null;
var traderPlugin = null;
var walletPlugin = null;
var idVerifierPlugin = null;

var currentlyUsedPlugins = {
  ticker: null,
  transfer: null,
  trader: null,
  idVerifier: null
};

var cachedConfig = null;
var deviceCurrency = 'USD';

var lastBalances = null;
var lastRates = {};

var balanceInterval = null;
var rateInterval = null;
var tradeInterval = null;

var tradesQueue = [];
var sessions = {};

// that's basically a constructor
exports.init = function init(databaseHandle) {
  if (!databaseHandle) {
    throw new Error('`db` is required');
  }

  db = databaseHandle;
};

function loadPlugin(name, config) {

  // plugins definitions
  var moduleMethods = {
    ticker: [ 'ticker' ],
    trader: [ 'balance', 'purchase', 'sell' ],
    wallet: [ 'balance', 'sendBitcoins' ],
    idVerifier: [ 'verifyUser', 'verifyTransaction' ]
  };

  var plugin = null;

  // each used plugin MUST be installed
  try {
    plugin = require('lamassu-' + name);

  } catch(_) {
    throw new Error(name + ' module is not installed. Try running \'npm install --save lamassu-' + name + '\' first');
  }

  // each plugin MUST implement those
  if (typeof plugin.SUPPORTED_MODULES !== 'undefined') {
    if(plugin.SUPPORTED_MODULES === 'string')
      plugin.SUPPORTED_MODULES = [plugin.SUPPORTED_MODULES];
  }

  if(!(plugin.SUPPORTED_MODULES instanceof Array))
    throw new Error('\'' + name + '\' fails to implement *required* \'SUPPORTED_MODULES\' constant');

  plugin.SUPPORTED_MODULES.forEach(function(moduleName) {
    moduleMethods[moduleName].forEach(function(methodName) {
      if (typeof plugin[methodName] !== 'function') {
        throw new Error('\'' + name + '\' declares \'' + moduleName + '\', but fails to implement \'' + methodName + '\' method');
      }
    });
  });

  // each plugin SHOULD implement those
  if (typeof plugin.NAME === 'undefined')
    logger.warn(new Error('\'' + name + '\' fails to implement *recommended* \'NAME\' field'));

  if (typeof plugin.config !== 'function') {
    logger.warn(new Error('\'' + name + '\' fails to implement *recommended* \'config\' method'));
    plugin.config = function() {};
  } else if (config !== null)
    plugin.config(config); // only when plugin supports it, and config is passed

  return plugin;
}

function loadOrConfigPlugin(pluginHandle, pluginType, currency, onChangeCb) {
  var currentName = cachedConfig.exchanges.plugins.current[pluginType];
  var pluginChanged = currentlyUsedPlugins[pluginType] !== currentName;

  if (currentName) { // some plugins may be disabled
    var pluginConfig = cachedConfig.exchanges.plugins.settings[currentName] || {};

    if (currency) pluginConfig.currency = currency;

    if (pluginHandle && !pluginChanged) pluginHandle.config(pluginConfig);
    else pluginHandle = loadPlugin(currentName, pluginConfig);
  }

  if (typeof onChangeCb === 'function') onChangeCb(pluginHandle, currency);

  return pluginHandle;
}

exports.configure = function configure(config) {
  if (config.exchanges.settings.lowBalanceMargin < 1) {
    throw new Error('`settings.lowBalanceMargin` has to be >= 1');
  }

  cachedConfig = config;

  // TICKER [required] configure (or load)
  loadOrConfigPlugin(
    tickerPlugin,
    'ticker',
    config.exchanges.settings.currency, // device currency
    function onTickerChange(newTicker, currency) {
      tickerPlugin = newTicker;
      pollRate();
    }
  );

  // WALLET [required] configure (or load)
  loadOrConfigPlugin(
    walletPlugin,
    'transfer',
    null,
    function onWalletChange(newWallet) {
      walletPlugin = newWallet;
      pollBalance();
    }
  );

  // TRADER [optional] configure (or load)
  traderPlugin = loadOrConfigPlugin(
    traderPlugin,
    'trade'
  );

  // ID VERIFIER [optional] configure (or load)
  idVerifierPlugin = loadOrConfigPlugin(
    idVerifierPlugin,
    'idVerifier'
  );
};
exports.getCachedConfig = function getCachedConfig() {
  return cachedConfig;
};

// This is where we record starting trade balance at the beginning
// of the user session
exports.trade = function trade(rawTrade, deviceFingerprint) {
  var sessionInfo = sessions[deviceFingerprint];

  if (!sessionInfo) {
    sessions[deviceFingerprint] = {
      timestamp: Date.now(),
      reaper: setTimeout(function() {
        delete sessions[deviceFingerprint];
      }, SESSION_TIMEOUT)
    };
  }

  tradesQueue.push({
    currency: rawTrade.currency,
    satoshis: rawTrade.satoshis
  });
};

exports.fiatBalance = function fiatBalance() {
  var rawRate = exports.getDeviceRate().rates.ask;
  var commission = cachedConfig.exchanges.settings.commission;

  if (!rawRate || !lastBalances) return null;

  // The rate is actually our commission times real rate.
  var rate = commission * rawRate;

  // `lowBalanceMargin` is our safety net. It's a number > 1, and we divide
  // all our balances by it to provide a safety margin.
  var lowBalanceMargin = cachedConfig.exchanges.settings.lowBalanceMargin;

  // `balance.transferBalance` is the balance of our transfer account (the one
  // we use to send Bitcoins to clients) in satoshis.
  var transferBalance = lastBalances.transferBalance.BTC;

  // Since `transferBalance` is in satoshis, we need to turn it into
  // bitcoins and then fiat to learn how much fiat currency we can exchange.
  //
  // Unit validity proof: [ $ ] = [ (B * 10^8) / 10^8 * $/B ]
  //                      [ $ ] = [ B * $/B ]
  //                      [ $ ] = [ $ ]
  var fiatTransferBalance = ((transferBalance / SATOSHI_FACTOR) * rate) / lowBalanceMargin;

  return fiatTransferBalance;
};

exports.sendBitcoins = function sendBitcoins(deviceFingerprint, tx, callback) {
  db.summonTransaction(deviceFingerprint, tx, function(err, txInfo) {
    if (err) return callback(err);

    if (!txInfo) {
      clearSession(deviceFingerprint);

      return walletPlugin.sendBitcoins(
        tx.toAddress,
        tx.satoshis,
        cachedConfig.exchanges.settings.transactionFee,

        function(err, txHash) {
          if (err) {
            var status = err.name === 'InsufficientFunds' ?
              'insufficientFunds' :
              'failed';

            db.reportTransactionError(tx, err.message, status);
            return callback(err);
          }

          db.completeTransaction(tx, txHash);
          pollBalance();
          callback(null, txHash);
        }
      );
    }

    // Out of bitcoins: special case
    var txErr = null;
    if (txInfo.err) {
      txErr = new Error(txInfo.err);
      if (txInfo.status === 'insufficientFunds') {
        txErr.name = 'InsufficientFunds';
      }
    }

    // transaction exists, but txHash might be null,
    // in which case ATM should continue polling
    pollBalance();
    callback(txErr, txInfo.txHash);
  });
};

/*
 * Polling livecycle
 */
exports.startPolling = function startPolling() {
  executeTrades();

  if (!balanceInterval) {
    balanceInterval = setInterval(pollBalance, POLLING_RATE);
  }

  if (!rateInterval) {
    rateInterval = setInterval(pollRate, POLLING_RATE);
  }

  // Always start trading, even if we don't have a trade exchange configured,
  // since configuration can always change in `Trader#configure`.
  // `Trader#executeTrades` returns early if we don't have a trade exchange
  // configured at the moment.
  if (!tradeInterval) {
    tradeInterval = setInterval(
      executeTrades,
      cachedConfig.exchanges.settings.tradeInterval
    );
  }
};

function pollBalance(callback) {
  logger.debug('collecting balance');

  var jobs = {
    transferBalance: walletPlugin.balance
  };

  // only add if trader is enabled
  // if (traderPlugin) {
  //   // NOTE: we would need to handle when traderCurrency!=deviceCurrency
  //   jobs.tradeBalance = traderPlugin.balance;
  // }

  async.parallel(jobs, function(err, balance) {
    if (err) {
      logger.error(err);
      return callback && callback(err);
    }

    logger.debug('Balance update:', balance);
    balance.timestamp = Date.now();
    lastBalances = balance;

    return callback && callback(null, lastBalances);
  });
}

function pollRate(callback) {
  logger.debug('polling for rates (' + tickerPlugin.NAME + ')');

  tickerPlugin.ticker(deviceCurrency, function(err, resRates) {
    if (err) {
      logger.error(err);
      return callback && callback(err);
    }

    logger.debug('got rates: %j', resRates);
    resRates.timestamp = new Date();
    lastRates = resRates;

    return callback && callback(null, lastRates);
  });
}

/*
 * Getters | Helpers
 */
function getLastRate(currency) {
  if (!lastRates) return null;

  var tmpCurrency = currency || deviceCurrency;
  if (!lastRates[tmpCurrency]) return null;

  return lastRates[tmpCurrency];
}
exports.getDeviceRate = function getDeviceRate() {
  return getLastRate(deviceCurrency);
};

exports.getBalance = function getBalance() {
  if (!lastBalances) return null;

  return lastBalances.transferBalance;
};

function clearSession(deviceFingerprint) {
  var session = sessions[deviceFingerprint];
  if (session) {
    clearTimeout(session.reaper);
    delete sessions[deviceFingerprint];
  }
}

/*
 * Trader functions
 */
function purchase(trade, callback) {
  traderPlugin.purchase(trade.satoshis, null, function(err) {
    if (err) return callback(err);
    pollBalance();
    if (typeof callback === 'function') callback();
  });
}

function consolidateTrades() {
  // NOTE: value in satoshis stays the same no matter the currency
  var consolidatedTrade = {
    currency: deviceCurrency,
    satoshis: tradesQueue.reduce(function(prev, current) {
      return prev + current.satoshis;
    }, 0)
  };

  tradesQueue = [];

  logger.debug('consolidated: ', JSON.stringify(consolidatedTrade));
  return consolidatedTrade;
}

function executeTrades() {
  if (!traderPlugin) return;

  logger.debug('checking for trades');

  var trade = consolidateTrades();

  if (trade.satoshis === 0) {
    logger.debug('rejecting 0 trade');
    return;
  }

  logger.debug('making a trade: %d', trade.satoshis / SATOSHI_FACTOR);
  purchase(trade, function(err) {
    if (err) {
      tradesQueue.push(trade);
      logger.error(err);
    }
  });
}

/*
 * ID Verifier functions
 */
exports.verifyUser = function verifyUser(data, callback) {
  idVerifierPlugin.verifyUser(data, callback);
};

exports.verifyTransaction = function verifyTransaction(data, callback) {
  idVerifierPlugin.verifyTransaction(data, callback);
};
<commit_msg>fix(ticker): Missing assignment added<commit_after>'use strict';

var async   = require('async');

var logger  = require('./logger');

var SATOSHI_FACTOR = 1e8;
var SESSION_TIMEOUT = 60 * 60 * 1000;
var POLLING_RATE = 60 * 1000; // poll each minute

var db = null;

var tickerPlugin = null;
var traderPlugin = null;
var walletPlugin = null;
var idVerifierPlugin = null;

var currentlyUsedPlugins = {
  ticker: null,
  transfer: null,
  trader: null,
  idVerifier: null
};

var cachedConfig = null;
var deviceCurrency = 'USD';

var lastBalances = null;
var lastRates = {};

var balanceInterval = null;
var rateInterval = null;
var tradeInterval = null;

var tradesQueue = [];
var sessions = {};

// that's basically a constructor
exports.init = function init(databaseHandle) {
  if (!databaseHandle) {
    throw new Error('`db` is required');
  }

  db = databaseHandle;
};

function loadPlugin(name, config) {

  // plugins definitions
  var moduleMethods = {
    ticker: [ 'ticker' ],
    trader: [ 'balance', 'purchase', 'sell' ],
    wallet: [ 'balance', 'sendBitcoins' ],
    idVerifier: [ 'verifyUser', 'verifyTransaction' ]
  };

  var plugin = null;

  // each used plugin MUST be installed
  try {
    plugin = require('lamassu-' + name);

  } catch(_) {
    throw new Error(name + ' module is not installed. Try running \'npm install --save lamassu-' + name + '\' first');
  }

  // each plugin MUST implement those
  if (typeof plugin.SUPPORTED_MODULES !== 'undefined') {
    if(plugin.SUPPORTED_MODULES === 'string')
      plugin.SUPPORTED_MODULES = [plugin.SUPPORTED_MODULES];
  }

  if(!(plugin.SUPPORTED_MODULES instanceof Array))
    throw new Error('\'' + name + '\' fails to implement *required* \'SUPPORTED_MODULES\' constant');

  plugin.SUPPORTED_MODULES.forEach(function(moduleName) {
    moduleMethods[moduleName].forEach(function(methodName) {
      if (typeof plugin[methodName] !== 'function') {
        throw new Error('\'' + name + '\' declares \'' + moduleName + '\', but fails to implement \'' + methodName + '\' method');
      }
    });
  });

  // each plugin SHOULD implement those
  if (typeof plugin.NAME === 'undefined')
    logger.warn(new Error('\'' + name + '\' fails to implement *recommended* \'NAME\' field'));

  if (typeof plugin.config !== 'function') {
    logger.warn(new Error('\'' + name + '\' fails to implement *recommended* \'config\' method'));
    plugin.config = function() {};
  } else if (config !== null)
    plugin.config(config); // only when plugin supports it, and config is passed

  return plugin;
}

function loadOrConfigPlugin(pluginHandle, pluginType, currency, onChangeCb) {
  var currentName = cachedConfig.exchanges.plugins.current[pluginType];
  var pluginChanged = currentlyUsedPlugins[pluginType] !== currentName;

  if (currentName) { // some plugins may be disabled
    var pluginConfig = cachedConfig.exchanges.plugins.settings[currentName] || {};

    if (currency) pluginConfig.currency = currency;

    if (pluginHandle && !pluginChanged) pluginHandle.config(pluginConfig);
    else pluginHandle = loadPlugin(currentName, pluginConfig);
  }

  if (typeof onChangeCb === 'function') onChangeCb(pluginHandle, currency);

  return pluginHandle;
}

exports.configure = function configure(config) {
  if (config.exchanges.settings.lowBalanceMargin < 1) {
    throw new Error('`settings.lowBalanceMargin` has to be >= 1');
  }

  cachedConfig = config;
  deviceCurrency = config.exchanges.settings.currency;

  // TICKER [required] configure (or load)
  loadOrConfigPlugin(
    tickerPlugin,
    'ticker',
    deviceCurrency, // device currency
    function onTickerChange(newTicker, currency) {
      tickerPlugin = newTicker;
      pollRate();
    }
  );

  // WALLET [required] configure (or load)
  loadOrConfigPlugin(
    walletPlugin,
    'transfer',
    null,
    function onWalletChange(newWallet) {
      walletPlugin = newWallet;
      pollBalance();
    }
  );

  // TRADER [optional] configure (or load)
  traderPlugin = loadOrConfigPlugin(
    traderPlugin,
    'trade'
  );

  // ID VERIFIER [optional] configure (or load)
  idVerifierPlugin = loadOrConfigPlugin(
    idVerifierPlugin,
    'idVerifier'
  );
};
exports.getCachedConfig = function getCachedConfig() {
  return cachedConfig;
};

// This is where we record starting trade balance at the beginning
// of the user session
exports.trade = function trade(rawTrade, deviceFingerprint) {
  var sessionInfo = sessions[deviceFingerprint];

  if (!sessionInfo) {
    sessions[deviceFingerprint] = {
      timestamp: Date.now(),
      reaper: setTimeout(function() {
        delete sessions[deviceFingerprint];
      }, SESSION_TIMEOUT)
    };
  }

  tradesQueue.push({
    currency: rawTrade.currency,
    satoshis: rawTrade.satoshis
  });
};

exports.fiatBalance = function fiatBalance() {
  var rawRate = exports.getDeviceRate().rates.ask;
  var commission = cachedConfig.exchanges.settings.commission;

  if (!rawRate || !lastBalances) return null;

  // The rate is actually our commission times real rate.
  var rate = commission * rawRate;

  // `lowBalanceMargin` is our safety net. It's a number > 1, and we divide
  // all our balances by it to provide a safety margin.
  var lowBalanceMargin = cachedConfig.exchanges.settings.lowBalanceMargin;

  // `balance.transferBalance` is the balance of our transfer account (the one
  // we use to send Bitcoins to clients) in satoshis.
  var transferBalance = lastBalances.transferBalance.BTC;

  // Since `transferBalance` is in satoshis, we need to turn it into
  // bitcoins and then fiat to learn how much fiat currency we can exchange.
  //
  // Unit validity proof: [ $ ] = [ (B * 10^8) / 10^8 * $/B ]
  //                      [ $ ] = [ B * $/B ]
  //                      [ $ ] = [ $ ]
  var fiatTransferBalance = ((transferBalance / SATOSHI_FACTOR) * rate) / lowBalanceMargin;

  return fiatTransferBalance;
};

exports.sendBitcoins = function sendBitcoins(deviceFingerprint, tx, callback) {
  db.summonTransaction(deviceFingerprint, tx, function(err, txInfo) {
    if (err) return callback(err);

    if (!txInfo) {
      clearSession(deviceFingerprint);

      return walletPlugin.sendBitcoins(
        tx.toAddress,
        tx.satoshis,
        cachedConfig.exchanges.settings.transactionFee,

        function(err, txHash) {
          if (err) {
            var status = err.name === 'InsufficientFunds' ?
              'insufficientFunds' :
              'failed';

            db.reportTransactionError(tx, err.message, status);
            return callback(err);
          }

          db.completeTransaction(tx, txHash);
          pollBalance();
          callback(null, txHash);
        }
      );
    }

    // Out of bitcoins: special case
    var txErr = null;
    if (txInfo.err) {
      txErr = new Error(txInfo.err);
      if (txInfo.status === 'insufficientFunds') {
        txErr.name = 'InsufficientFunds';
      }
    }

    // transaction exists, but txHash might be null,
    // in which case ATM should continue polling
    pollBalance();
    callback(txErr, txInfo.txHash);
  });
};

/*
 * Polling livecycle
 */
exports.startPolling = function startPolling() {
  executeTrades();

  if (!balanceInterval) {
    balanceInterval = setInterval(pollBalance, POLLING_RATE);
  }

  if (!rateInterval) {
    rateInterval = setInterval(pollRate, POLLING_RATE);
  }

  // Always start trading, even if we don't have a trade exchange configured,
  // since configuration can always change in `Trader#configure`.
  // `Trader#executeTrades` returns early if we don't have a trade exchange
  // configured at the moment.
  if (!tradeInterval) {
    tradeInterval = setInterval(
      executeTrades,
      cachedConfig.exchanges.settings.tradeInterval
    );
  }
};

function pollBalance(callback) {
  logger.debug('collecting balance');

  var jobs = {
    transferBalance: walletPlugin.balance
  };

  // only add if trader is enabled
  // if (traderPlugin) {
  //   // NOTE: we would need to handle when traderCurrency!=deviceCurrency
  //   jobs.tradeBalance = traderPlugin.balance;
  // }

  async.parallel(jobs, function(err, balance) {
    if (err) {
      logger.error(err);
      return callback && callback(err);
    }

    logger.debug('Balance update:', balance);
    balance.timestamp = Date.now();
    lastBalances = balance;

    return callback && callback(null, lastBalances);
  });
}

function pollRate(callback) {
  logger.debug('polling for rates (' + tickerPlugin.NAME + ')');

  tickerPlugin.ticker(deviceCurrency, function(err, resRates) {
    if (err) {
      logger.error(err);
      return callback && callback(err);
    }

    logger.debug('got rates: %j', resRates);
    resRates.timestamp = new Date();
    lastRates = resRates;

    return callback && callback(null, lastRates);
  });
}

/*
 * Getters | Helpers
 */
function getLastRate(currency) {
  if (!lastRates) return null;

  var tmpCurrency = currency || deviceCurrency;
  if (!lastRates[tmpCurrency]) return null;

  return lastRates[tmpCurrency];
}
exports.getDeviceRate = function getDeviceRate() {
  return getLastRate(deviceCurrency);
};

exports.getBalance = function getBalance() {
  if (!lastBalances) return null;

  return lastBalances.transferBalance;
};

function clearSession(deviceFingerprint) {
  var session = sessions[deviceFingerprint];
  if (session) {
    clearTimeout(session.reaper);
    delete sessions[deviceFingerprint];
  }
}

/*
 * Trader functions
 */
function purchase(trade, callback) {
  traderPlugin.purchase(trade.satoshis, null, function(err) {
    if (err) return callback(err);
    pollBalance();
    if (typeof callback === 'function') callback();
  });
}

function consolidateTrades() {
  // NOTE: value in satoshis stays the same no matter the currency
  var consolidatedTrade = {
    currency: deviceCurrency,
    satoshis: tradesQueue.reduce(function(prev, current) {
      return prev + current.satoshis;
    }, 0)
  };

  tradesQueue = [];

  logger.debug('consolidated: ', JSON.stringify(consolidatedTrade));
  return consolidatedTrade;
}

function executeTrades() {
  if (!traderPlugin) return;

  logger.debug('checking for trades');

  var trade = consolidateTrades();

  if (trade.satoshis === 0) {
    logger.debug('rejecting 0 trade');
    return;
  }

  logger.debug('making a trade: %d', trade.satoshis / SATOSHI_FACTOR);
  purchase(trade, function(err) {
    if (err) {
      tradesQueue.push(trade);
      logger.error(err);
    }
  });
}

/*
 * ID Verifier functions
 */
exports.verifyUser = function verifyUser(data, callback) {
  idVerifierPlugin.verifyUser(data, callback);
};

exports.verifyTransaction = function verifyTransaction(data, callback) {
  idVerifierPlugin.verifyTransaction(data, callback);
};
<|endoftext|>


<commit_before>const debug = require('debug')('express-dom');

exports.types = function types(page, settings) {
	settings.filters.push(request => {
		return settings.types.has(request.resourceType());
	});
};

exports.domain = function cors(page, settings) {
	const { domain } = settings;
	if (domain == "none") settings.filters.push(() => false);
	else if (domain == "same") settings.filters.push(request => {
		const pageUrl = new URL(page.url());
		const url = new URL(request.url());
		return pageUrl.hostname == url.hostname;
	});
};

exports.absolute = function absolute(page) {
	page.on('idle', () => {
		return page.evaluate(() => {
			const dloc = document.location;
			const base = dloc.protocol + '//' + dloc.host;
			const nodes = [
				['a', 'href'],
				['img', 'src'],
				['video', 'src'],
				['object', 'src'],
				['link', 'href'],
				['script', 'src'],
				['include', 'src']
			];
			for (const [sel, att] of nodes) {
				for (const node of document.querySelectorAll(sel)) {
					const item = node.attributes.getNamedItem(att);
					if (!item) continue;
					const uloc = new URL(item.nodeValue, base);
					item.nodeValue = uloc.href;
				}
			}
		});
	});
};

exports.mount = function mount(page) {
	page.on('idle', () => {
		return page.evaluate(() => {
			const dloc = document.location;
			const base = dloc.protocol + '//' + dloc.host;
			const nodes = [
				['a', 'href'],
				['img', 'src'],
				['video', 'src'],
				['object', 'src'],
				['link', 'href'],
				['script', 'src'],
				['include', 'src']
			];
			for (const [sel, att] of nodes) {
				for (const node of document.querySelectorAll(sel)) {
					const item = node.attributes.getNamedItem(att);
					if (!item) continue;
					const val = item.nodeValue;
					if (!val || val.charAt(0) == '#') continue;
					const uloc = new URL(val, base);
					if (uloc.protocol == dloc.protocol && uloc.host == dloc.host) {
						item.nodeValue = uloc.pathname + uloc.search + uloc.hash;
					}
				}
			}
		});
	});
};

exports.html = async function(page, settings, request, response) {
	page.on('idle', async () => {
		debug("html plugin idle");
		if (settings.output == null) {
			settings.output = await page.content();
		}
	});
};

exports.redirect = function (page, settings, req, res) {
	settings.filters.push(request => {
		if (request.isNavigationRequest()) {
			res.status(302);
			res.set('Location', request.url());
			debug("page redirected");
			return false;
		}
	});
};

exports.referrer = function(page, settings, req) {
	const referrer = req.get('Referer');
	if (referrer) page.route(settings.location.toString(), async (route, request) => {
		const headers = await request.allHeaders();
		route.continue({
			headers: {
				...headers,
				referrer
			}
		});
	});
};

exports.prerender = async function(page, settings) {
	await page.addInitScript(`
		Object.defineProperty(document, "visibilityState", {
			configurable: true,
			get: function() { return "prerender"; }
		});
	`);
};

exports.hide = async function hide(page, settings) {
	if (settings.hide === false) return;
	await page.addInitScript(`
		Object.defineProperty(document, "hidden", {
			configurable: true,
			get: function() { return true; }
		});
	`);
	page.addStyleTag({
		content: `html {
			display:none !important;
		}
		* {
			-webkit-transition:none !important;
			transition:none !important;
			-webkit-transition-property: none !important;
			transition-property: none !important;
			-webkit-transform: none !important;
			transform: none !important;
			-webkit-animation: none !important;
			animation: none !important;
		}`});
	settings.types.delete('stylesheet');
	settings.types.delete('image');
	settings.types.delete('font');
};

exports.cookies = function cookies(page, settings, request) {
	const { cookies } = request;
	const { allowedCookies } = settings;
	const list = [];
	const names = [];
	for (const name in cookies) {
		if (allowedCookies == null || allowedCookies.has(name)) {
			names.push(name);
			cookies.push({ name, value: cookies[name] });
		}
	}
	debug("settings cookies", names);
	return page.context().addCookies(list);
};

exports.png = function png(page, settings, request, response) {
	settings.hide = false;
	settings.types.add('image');
	settings.types.add('stylesheet');
	settings.types.add('font');

	page.on('idle', async () => {
		settings.output = await page.screenshot({
			animations: false,
			fullPage: true,
			scale: "css",
			type: "png",
			timeout: 5000
		});
		response.set('Content-Type', 'image/png');
	});
};

exports.httpequivs = function(page, settings, request, response) {
	page.on('idle', async () => {
		const equivs = await page.evaluate(() => {
			const equivs = {};
			for (const node of document.querySelectorAll('head > meta[http-equiv]')) {
				const list = (node.content || '').split(',');
				let vals = equivs[node.httpEquiv];
				if (!vals) vals = equivs[node.httpEquiv] = new Set();
				for (const str of list) {
					if (vals.includes(str) == false) vals.add(str);
				}
				node.remove();
			}
			return equivs;
		});
		if (equivs.Status?.length) {
			delete equivs.Status;
			const code = parseInt(status.pop());
			// the list of authorized Status codes
			if (!Number.isNaN(code) && [200, 301, 302, 400, 401, 403, 404, 451, 500].indexOf(code) >= 0) {
				response.status(code);
			} else {
				// eslint-disable-next-line no-console
				console.warn("express-dom got http-equiv Status with invalid value", status);
			}
		}
		for (const [name, equiv] of Object.entries(equivs)) {
			let vals = response.get(name);
			if (!vals) {
				vals = new Set();
			} else if (typeof vals == "string") {
				vals = new Set([vals]);
			}
			for (const str of equiv) {
				vals.add(str);
			}
			response.set(name, Array.from(vals).join(','));
		}
	});
};

exports.httplinkpreload = function(page, settings, request, response) {
	page.on('idle', async () => {
		const links = await page.evaluate(() => {
			const loc = document.location;
			return Array.from(
				document.querySelectorAll('link[href][rel="stylesheet"],script[src]')
			).map((node) => {
				const url = new URL(node.href || node.src, loc);
				const remote = url.host != loc.host;
				return {
					as: node.nodeName == "LINK" ? "style" : "script",
					href: remote ? url.href : url.pathname + url.search,
					remote: remote,
					crossOrigin: node.crossOrigin
				};
			});
		});
		if (links.length) response.append('Link', links.map((obj) => {
			const nopush = obj.remote ? ';nopush' : '';
			const crossOrigin = obj.crossOrigin ? ';crossorigin=' + obj.crossOrigin : '';
			return `<${obj.href}>;rel=preload;as=${obj.as}` + nopush + crossOrigin;
		}).join(','));
	});
};

<commit_msg>req, res comes from express<commit_after>const debug = require('debug')('express-dom');

exports.types = function types(page, settings) {
	settings.filters.push(request => {
		return settings.types.has(request.resourceType());
	});
};

exports.domain = function cors(page, settings) {
	const { domain } = settings;
	if (domain == "none") settings.filters.push(() => false);
	else if (domain == "same") settings.filters.push(request => {
		const pageUrl = new URL(page.url());
		const url = new URL(request.url());
		return pageUrl.hostname == url.hostname;
	});
};

exports.absolute = function absolute(page) {
	page.on('idle', () => {
		return page.evaluate(() => {
			const dloc = document.location;
			const base = dloc.protocol + '//' + dloc.host;
			const nodes = [
				['a', 'href'],
				['img', 'src'],
				['video', 'src'],
				['object', 'src'],
				['link', 'href'],
				['script', 'src'],
				['include', 'src']
			];
			for (const [sel, att] of nodes) {
				for (const node of document.querySelectorAll(sel)) {
					const item = node.attributes.getNamedItem(att);
					if (!item) continue;
					const uloc = new URL(item.nodeValue, base);
					item.nodeValue = uloc.href;
				}
			}
		});
	});
};

exports.mount = function mount(page) {
	page.on('idle', () => {
		return page.evaluate(() => {
			const dloc = document.location;
			const base = dloc.protocol + '//' + dloc.host;
			const nodes = [
				['a', 'href'],
				['img', 'src'],
				['video', 'src'],
				['object', 'src'],
				['link', 'href'],
				['script', 'src'],
				['include', 'src']
			];
			for (const [sel, att] of nodes) {
				for (const node of document.querySelectorAll(sel)) {
					const item = node.attributes.getNamedItem(att);
					if (!item) continue;
					const val = item.nodeValue;
					if (!val || val.charAt(0) == '#') continue;
					const uloc = new URL(val, base);
					if (uloc.protocol == dloc.protocol && uloc.host == dloc.host) {
						item.nodeValue = uloc.pathname + uloc.search + uloc.hash;
					}
				}
			}
		});
	});
};

exports.html = async function(page, settings, req, res) {
	page.on('idle', async () => {
		debug("html plugin idle");
		if (settings.output == null) {
			settings.output = await page.content();
		}
	});
};

exports.redirect = function (page, settings, req, res) {
	settings.filters.push(request => {
		if (request.isNavigationRequest()) {
			res.status(302);
			res.set('Location', request.url());
			debug("page redirected");
			return false;
		}
	});
};

exports.referrer = function(page, settings, req) {
	const referrer = req.get('Referer');
	if (referrer) page.route(settings.location.toString(), async (route, request) => {
		const headers = await request.allHeaders();
		route.continue({
			headers: {
				...headers,
				referrer
			}
		});
	});
};

exports.prerender = async function(page, settings) {
	await page.addInitScript(`
		Object.defineProperty(document, "visibilityState", {
			configurable: true,
			get: function() { return "prerender"; }
		});
	`);
};

exports.hide = async function hide(page, settings) {
	if (settings.hide === false) return;
	await page.addInitScript(`
		Object.defineProperty(document, "hidden", {
			configurable: true,
			get: function() { return true; }
		});
	`);
	page.addStyleTag({
		content: `html {
			display:none !important;
		}
		* {
			-webkit-transition:none !important;
			transition:none !important;
			-webkit-transition-property: none !important;
			transition-property: none !important;
			-webkit-transform: none !important;
			transform: none !important;
			-webkit-animation: none !important;
			animation: none !important;
		}`});
	settings.types.delete('stylesheet');
	settings.types.delete('image');
	settings.types.delete('font');
};

exports.cookies = function cookies(page, settings, request) {
	const { cookies } = request;
	const { allowedCookies } = settings;
	const list = [];
	const names = [];
	for (const name in cookies) {
		if (allowedCookies == null || allowedCookies.has(name)) {
			names.push(name);
			cookies.push({ name, value: cookies[name] });
		}
	}
	debug("settings cookies", names);
	return page.context().addCookies(list);
};

exports.png = function png(page, settings, request, response) {
	settings.hide = false;
	settings.types.add('image');
	settings.types.add('stylesheet');
	settings.types.add('font');

	page.on('idle', async () => {
		settings.output = await page.screenshot({
			animations: false,
			fullPage: true,
			scale: "css",
			type: "png",
			timeout: 5000
		});
		response.set('Content-Type', 'image/png');
	});
};

exports.httpequivs = function(page, settings, request, response) {
	page.on('idle', async () => {
		const equivs = await page.evaluate(() => {
			const equivs = {};
			for (const node of document.querySelectorAll('head > meta[http-equiv]')) {
				const list = (node.content || '').split(',');
				let vals = equivs[node.httpEquiv];
				if (!vals) vals = equivs[node.httpEquiv] = new Set();
				for (const str of list) {
					if (vals.includes(str) == false) vals.add(str);
				}
				node.remove();
			}
			return equivs;
		});
		if (equivs.Status?.length) {
			delete equivs.Status;
			const code = parseInt(status.pop());
			// the list of authorized Status codes
			if (!Number.isNaN(code) && [200, 301, 302, 400, 401, 403, 404, 451, 500].indexOf(code) >= 0) {
				response.status(code);
			} else {
				// eslint-disable-next-line no-console
				console.warn("express-dom got http-equiv Status with invalid value", status);
			}
		}
		for (const [name, equiv] of Object.entries(equivs)) {
			let vals = response.get(name);
			if (!vals) {
				vals = new Set();
			} else if (typeof vals == "string") {
				vals = new Set([vals]);
			}
			for (const str of equiv) {
				vals.add(str);
			}
			response.set(name, Array.from(vals).join(','));
		}
	});
};

exports.httplinkpreload = function(page, settings, request, response) {
	page.on('idle', async () => {
		const links = await page.evaluate(() => {
			const loc = document.location;
			return Array.from(
				document.querySelectorAll('link[href][rel="stylesheet"],script[src]')
			).map((node) => {
				const url = new URL(node.href || node.src, loc);
				const remote = url.host != loc.host;
				return {
					as: node.nodeName == "LINK" ? "style" : "script",
					href: remote ? url.href : url.pathname + url.search,
					remote: remote,
					crossOrigin: node.crossOrigin
				};
			});
		});
		if (links.length) response.append('Link', links.map((obj) => {
			const nopush = obj.remote ? ';nopush' : '';
			const crossOrigin = obj.crossOrigin ? ';crossorigin=' + obj.crossOrigin : '';
			return `<${obj.href}>;rel=preload;as=${obj.as}` + nopush + crossOrigin;
		}).join(','));
	});
};

<|endoftext|>


<commit_before>import MagnonElement from "../../src/magnon-element.js";

import html from "./notification.content.js";
import css from "./notification.style.js";

import "../magnon-styles/magnon-styles.js";
import "../magnon-icon/magnon-icon.js";
import "../magnon-icon-button/magnon-icon-button.js";

export class MagnonNotification extends MagnonElement {
    constructor() {
        super({ content: html + css });
    }

    static get elementName() {
        return "magnon-notification";
    }

    static get propertyAttributes() {
        return {
            string: ["color"]
        };
    }

    contentReady() {
        const margin = window.getComputedStyle(this).margin;

        this.style.transition = "none";
        this.style.height = "0px";
        this.style.margin = "0px 0px";

        this.root.querySelector(".close-button").addEventListener("click", () => this.close());

        setTimeout(() => {
            this.style.height = "";
            const height = this.offsetHeight;

            this.style.height = "0px";

            setTimeout(() => {
                this.style.transition = "";

                this.style.margin = margin;
                this.style.height = `${height}px`;

                this.addEventListener("animationstart", () => {
                    this.style.opacity = 1;
                });
            }, 100);
        }, 100);
    }

    propertySet(property, old, value) {
        if (property === "color") {
            const newValue = value.startsWith("--") ? `var(${value})` : value;
            this.style.setProperty("--magnon-notification-color", newValue);
        }
    }

    close() {
        this.fire("close");

        this.style.transform = "scaleY(0)";
        const end = () => {
            this.style.height = "0px";
            this.style.margin = "0px";
            this.removeEventListener("transitionend", end);
            const newEnd = () => {
                this.parentElement.removeChild(this);
                this.removeEventListener("transitionend", newEnd);
            };
            this.addEventListener("transitionend", newEnd);
        };
        this.addEventListener("transitionend", end);
    }
}

MagnonNotification.init();
<commit_msg>Fix notification creation in webkit<commit_after>import MagnonElement from "../../src/magnon-element.js";

import html from "./notification.content.js";
import css from "./notification.style.js";

import "../magnon-styles/magnon-styles.js";
import "../magnon-icon/magnon-icon.js";
import "../magnon-icon-button/magnon-icon-button.js";

export class MagnonNotification extends MagnonElement {
    constructor() {
        super({ content: html + css });
    }

    static get elementName() {
        return "magnon-notification";
    }

    static get propertyAttributes() {
        return {
            string: ["color"]
        };
    }

    contentReady() {
        this.root.querySelector(".close-button").addEventListener("click", () => this.close());

        requestAnimationFrame(() => {
            const margin = window.getComputedStyle(this).margin;

            this.style.transition = "none";
            this.style.height = "0px";
            this.style.margin = "0px 0px";

            setTimeout(() => {
                this.style.height = "";
                const height = this.offsetHeight;

                this.style.height = "0px";

                setTimeout(() => {
                    this.style.transition = "";

                    this.style.margin = margin;
                    this.style.height = `${height}px`;

                    this.addEventListener("animationstart", () => {
                        this.style.opacity = 1;
                    });
                }, 100);
            }, 100);
        });
    }

    propertySet(property, old, value) {
        if (property === "color") {
            const newValue = value.startsWith("--") ? `var(${value})` : value;
            this.style.setProperty("--magnon-notification-color", newValue);
        }
    }

    close() {
        this.fire("close");

        this.style.transform = "scaleY(0)";
        const end = () => {
            this.style.height = "0px";
            this.style.margin = "0px";
            this.removeEventListener("transitionend", end);
            const newEnd = () => {
                this.parentElement.removeChild(this);
                this.removeEventListener("transitionend", newEnd);
            };
            this.addEventListener("transitionend", newEnd);
        };
        this.addEventListener("transitionend", end);
    }
}

MagnonNotification.init();
<|endoftext|>


<commit_before>define(['js/core/Component'], function(Component) {
    return Component.inherit('srv.core.Handler', {

        defaults: {
            path: "/",
            route: null
        },

        _initializationComplete: function() {
            if (!this.$.path) {
                throw new Error("Relative path for module missing");
            }
        },

        /***
         * starts the handler
         * @param server
         * @param callback
         */
        start: function(server, callback) {
            callback();
        },

        stop: function(callback){
            callback();
        },

        isResponsibleForRequest: function(context) {

            // Check path
            var path = context.request.urlInfo.pathname;

            if (path.indexOf(this.$.path) === 0) {
                // path matches
                if (this.$.route !== null) {
                    return (new RegExp(this.$.route, "i")).test(path);
                }

                return true;
            }

            return false;
        },

        /***
         * returns an handler instance to process the request
         * @return {srv.core.Handler}
         */
        getHandlerInstance: function() {
            return this;
        },

        /***
         * handles the request
         * @param {srv.core.ServerContext} context
         * @param {Function} callback - callback can be used to report an asynchronous error
         */
        handleRequest: function(context, callback) {
            throw new Error("Abstract method processRequest");
        }
    })
});<commit_msg>doc Handler<commit_after>define(['js/core/Component'], function(Component) {
    return Component.inherit('srv.core.Handler', {

        defaults: {
            path: "/",
            route: null
        },

        _initializationComplete: function() {
            if (!this.$.path) {
                throw new Error("Relative path for module missing");
            }
        },

        /***
         * starts the handler
         * @param server
         * @param callback
         */
        start: function(server, callback) {
            callback();
        },

        stop: function(callback){
            callback();
        },

        /***
         *
         * @param {srv.core.HttpContext} context
         * @return {Boolean}
         */
        isResponsibleForRequest: function(context) {

            // Check path
            var path = context.request.urlInfo.pathname;

            if (path.indexOf(this.$.path) === 0) {
                // path matches
                if (this.$.route !== null) {
                    return (new RegExp(this.$.route, "i")).test(path);
                }

                return true;
            }

            return false;
        },

        /***
         * returns an handler instance to process the request
         * @return {srv.core.Handler}
         */
        getHandlerInstance: function() {
            return this;
        },

        /***
         * handles the request
         * @param {srv.core.ServerContext} context
         * @param {Function} callback - callback can be used to report an asynchronous error
         */
        handleRequest: function(context, callback) {
            throw new Error("Abstract method processRequest");
        }
    })
});<|endoftext|>