<commit_before>/**
 * Mobility - Mobility is a super light weight HTML,
 * CSS, and JS framework built on top of Bootstrap
 * for developing mobile applications.
 *
 * @version 0.0.1
 * @author Christian Blanquera <cblanquera@openovate.com>
 * @website https://github.com/cblanquera/mobility
 * @license MIT
 */
(function($) {
	$(window).on('go-back-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('go-back-click', e.target);
		var target = getTarget(trigger);

		try {
			if($(target).length && $(target).html()) {
				$.mobility.swap($(target).html(), 'slide-right');
			}
		} catch(e) {}

		$(window).trigger('mobility-request', [target, 'slide-right']);
	}).on('go-forward-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('go-back-click', e.target);
		var target = getTarget(trigger);

		try {
			if($(target).length && $(target).html()) {
				$.mobility.swap($(target).html(), 'slide-left');
			}
		} catch(e) {}

		$(window).trigger('mobility-request', [target, 'slide-left']);
	}).on('focus-input-group-init', function(e, trigger) {
		trigger = $(trigger);

		trigger.find('label').each(function() {
			$(this).click(function() {
				trigger.find('label input').each(function() {
					if(this.checked) {
						$(this).parents('label:first').addClass('active');
					} else {
						$(this).parents('label:first').removeClass('active');
					}
				});
			});
		})

	}).on('tab-switch-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('tab-switch-click', e.target);
		var target = $(getTarget(trigger));

		trigger.siblings().each(function() {
			var target = $(this).removeClass('active').attr('href');
			$(target).addClass('hide');
		});

		trigger.addClass('active');
		target.removeClass('hide');
	}).on('modal-open-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		if($.mobility.busy) {
			return;
		}

		$.mobility.busy = true;

		var trigger = getTrigger('modal-open-click', e.target);
		var target = $(getTarget(trigger));

		var slideEnd = function () {
			target
				.unbind('webkitTransitionEnd', slideEnd)
				.removeClass('sliding');

			$.mobility.busy = false;
		};

		target
			.addClass('sliding-down')
			.removeClass('hide');

		target[0].offsetWidth; // force reflow

		target
			.removeClass('sliding-down')
			.on('webkitTransitionEnd', slideEnd)
			.addClass('sliding');

	}).on('modal-close-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		if($.mobility.busy) {
			return;
		}

		$.mobility.busy = true;

		var trigger = getTrigger('modal-close-click', e.target);
		var target = $(getTarget(trigger));

		var slideEnd = function () {
			target
				.unbind('webkitTransitionEnd', slideEnd)
				.removeClass('sliding')
				.removeClass('sliding-down')
				.addClass('hide');

			$.mobility.busy = false;
		};

		target[0].offsetWidth; // force reflow

		target
			.on('webkitTransitionEnd', slideEnd)
			.addClass('sliding')
			.addClass('sliding-down');

	}).on('popover-open-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('popover-open-click', e.target);
		var target = $(getTarget(trigger));

		target.removeClass('hide');
	}).on('popover-close-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('popover-close-click', e.target);
		var target = $(getTarget(trigger));

		target.addClass('hide');
	});

	var getTrigger = function(event, target) {
		var i, subject, events, trigger = null;

		target = $(target);

		if(target.attr('data-do') && target.attr('data-on')) {
			subject = target.attr('data-do')
			events 	= target.attr('data-on').split('|');

			events.unshift('init');

			for(i = 0; i < events.length; i++) {
				if((subject + '-' + events[i]) === event) {
					return target;
				}
			}
		}

		target.parents('[data-do]').each(function() {
			if(trigger) {
				return false;
			}

			subject = $(this).attr('data-do')
			events = $(this).attr('data-on').split('|');

			events.unshift('init');

			for(i = 0; i < events.length; i++) {
				if((subject + '-' + events[i]) === event) {
					trigger = $(this);
					return false;
				}
			}
		});

		return trigger || target;
	};

	var getTarget = function(trigger) {
		trigger = $(trigger);

		var target = trigger.attr('data-target');

		if(!target || !target.length) {
			target = trigger.attr('href');
		}

		return target;
	};

	$.extend({
		mobility: {
			busy: false,
			swap: function(html, effect) {
				if($.mobility.busy) {
					return;
				}

				$.mobility.busy = true;

				var section = $('
').html(html);
				var current = $('section.screen.current');

				var slideEnd = function () {
					section
						.unbind('webkitTransitionEnd', slideEnd)
						.removeClass('sliding')
						.removeClass('sliding-up')
						.removeClass('sliding-right')
						.removeClass('sliding-down')
						.removeClass('sliding-left');

					current.remove();

					$.mobility.busy = false;
				};

				var fadeEnd = function () {
					current.remove();

					$.mobility.busy = false;
				};

				switch(effect) {
					case 'slide-left':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-right');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-right')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-left');
						break;

					case 'slide-right':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-left');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-left')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-right');

						break;

					case 'slide-up':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-down');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-down')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-up');
						break;

					case 'slide-down':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-up');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-up')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-down');
						break;

					case 'fade':
						$(document.body).prepend(section);

						section.doon();

						current
							.on('webkitTransitionEnd', fadeEnd)
							.addClass('fade');

						break;

					default:
						section.appendTo(document.body).doon();
						current.remove();

						$.mobility.busy = true;
						break;

				}
			},

			start: function() {
				$(document.body).doon();
			}
		}
	});
})(jQuery);<commit_msg>hotfix<commit_after>/**
 * Mobility - Mobility is a super light weight HTML,
 * CSS, and JS framework built on top of Bootstrap
 * for developing mobile applications.
 *
 * @version 0.0.1
 * @author Christian Blanquera <cblanquera@openovate.com>
 * @website https://github.com/cblanquera/mobility
 * @license MIT
 */
(function($) {
	$(window).on('go-back-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('go-back-click', e.target);
		var target = getTarget(trigger);

		try {
			if($(target).length && $(target).html()) {
				$.mobility.swap($(target).html(), 'slide-right');
			}
		} catch(e) {}

		$(window).trigger('mobility-request', [target, 'slide-right']);
	}).on('go-forward-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('go-back-click', e.target);
		var target = getTarget(trigger);

		try {
			if($(target).length && $(target).html()) {
				$.mobility.swap($(target).html(), 'slide-left');
			}
		} catch(e) {}

		$(window).trigger('mobility-request', [target, 'slide-left']);
	}).on('focus-input-group-init', function(e, trigger) {
		trigger = $(trigger);

		trigger.find('label').each(function() {
			$(this).click(function() {
				trigger.find('label input').each(function() {
					if(this.checked) {
						$(this).parents('label:first').addClass('active');
					} else {
						$(this).parents('label:first').removeClass('active');
					}
				});
			});
		})

	}).on('tab-switch-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('tab-switch-click', e.target);
		var target = $(getTarget(trigger));

		trigger.siblings().each(function() {
			var target = $(this).removeClass('active').attr('href');
			$(target).addClass('hide');
		});

		trigger.addClass('active');
		target.removeClass('hide');
	}).on('modal-open-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		if($.mobility.busy) {
			return;
		}

		$.mobility.busy = true;

		var trigger = getTrigger('modal-open-click', e.target);
		var target = $(getTarget(trigger));

		var slideEnd = function () {
			target
				.unbind('webkitTransitionEnd', slideEnd)
				.removeClass('sliding');

			$.mobility.busy = false;
		};

		target
			.addClass('sliding-down')
			.removeClass('hide');

		target[0].offsetWidth; // force reflow

		target
			.removeClass('sliding-down')
			.on('webkitTransitionEnd', slideEnd)
			.addClass('sliding');

	}).on('modal-close-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		if($.mobility.busy) {
			return;
		}

		$.mobility.busy = true;

		var trigger = getTrigger('modal-close-click', e.target);
		var target = $(getTarget(trigger));

		var slideEnd = function () {
			target
				.unbind('webkitTransitionEnd', slideEnd)
				.removeClass('sliding')
				.removeClass('sliding-down')
				.addClass('hide');

			$.mobility.busy = false;
		};

		target[0].offsetWidth; // force reflow

		target
			.on('webkitTransitionEnd', slideEnd)
			.addClass('sliding')
			.addClass('sliding-down');

	}).on('popover-open-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('popover-open-click', e.target);
		var target = $(getTarget(trigger));

		target.removeClass('hide');
	}).on('popover-close-click', function(e) {
		e.preventDefault();
		e.originalEvent.stop = true;

		var trigger = getTrigger('popover-close-click', e.target);
		var target = $(getTarget(trigger));

		target.addClass('hide');
	});

	var getTrigger = function(event, target) {
		var i, subject, events, trigger = null;

		target = $(target);

		if(target.attr('data-do') && target.attr('data-on')) {
			subject = target.attr('data-do')
			events 	= target.attr('data-on').split('|');

			events.unshift('init');

			for(i = 0; i < events.length; i++) {
				if((subject + '-' + events[i]) === event) {
					return target;
				}
			}
		}

		target.parents('[data-do]').each(function() {
			if(trigger) {
				return false;
			}

			subject = $(this).attr('data-do')
			events = $(this).attr('data-on').split('|');

			events.unshift('init');

			for(i = 0; i < events.length; i++) {
				if((subject + '-' + events[i]) === event) {
					trigger = $(this);
					return false;
				}
			}
		});

		return trigger || target;
	};

	var getTarget = function(trigger) {
		trigger = $(trigger);

		var target = trigger.attr('data-target');

		if(!target || !target.length) {
			target = trigger.attr('href');
		}

		return target;
	};

	$.extend({
		mobility: {
			busy: false,
			swap: function(html, effect) {
				if($.mobility.busy) {
					return;
				}

				$.mobility.busy = true;

				var section = $('
').html(html);
				var current = $('section.screen.current');

				var slideEnd = function () {
					section
						.unbind('webkitTransitionEnd', slideEnd)
						.removeClass('sliding')
						.removeClass('sliding-up')
						.removeClass('sliding-right')
						.removeClass('sliding-down')
						.removeClass('sliding-left');

					current.remove();

					$.mobility.busy = false;
				};

				var fadeEnd = function () {
					current.remove();

					$.mobility.busy = false;
				};

				switch(effect) {
					case 'slide-left':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-right');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-right')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-left');
						break;

					case 'slide-right':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-left');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-left')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-right');

						break;

					case 'slide-up':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-down');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-down')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-up');
						break;

					case 'slide-down':
						$(document.body).append(section);

						section
							.doon()
							.addClass('sliding-up');

						section[0].offsetWidth; // force reflow

						section
							.removeClass('sliding-up')
							.on('webkitTransitionEnd', slideEnd)
							.addClass('sliding');

						current
							.addClass('sliding')
							.addClass('sliding-down');
						break;

					case 'fade':
						$(document.body).prepend(section);

						section.doon();

						current
							.on('webkitTransitionEnd', fadeEnd)
							.addClass('fade');

						break;

					default:
						section.appendTo(document.body).doon();
						current.remove();

						$.mobility.busy = false;
						break;

				}
			},

			start: function() {
				$(document.body).doon();
			}
		}
	});
})(jQuery);<|endoftext|>


<commit_before>/* This file is part of Indico.
 * Copyright (C) 2002 - 2017 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

import {createHash} from 'crypto';
import chalk from 'chalk';
import fs from 'fs';
import path from 'path';

import webpack from 'webpack';

import ExtractTextPlugin from 'extract-text-webpack-plugin';
import ManifestPlugin from 'webpack-manifest-plugin';
import ProgressBarPlugin from 'progress-bar-webpack-plugin';
import importOnce from 'node-sass-import-once';

function _resolveTheme(rootPath, indicoClientPath, filePath) {
    const indicoRelativePath = path.resolve(indicoClientPath, filePath);

    if (indicoClientPath && !fs.existsSync(path.resolve(rootPath, filePath)) &&
            fs.existsSync(indicoRelativePath)) {
        return path.resolve(indicoClientPath, filePath);
    }

    return path.resolve(rootPath, filePath);
}

export function getThemeEntryPoints(config, prefix) {
    const themes = config.themes;
    const indicoClientPath = path.join(config.isPlugin ? config.indico.build.clientPath : config.build.clientPath,
                                       'styles');
    const rootPath = path.join(config.build.rootPath);

    return Object.assign(...Object.keys(themes).map((k) => {
        const returnValue = {};
        const escapedKey = k.replace('-', '_');

        returnValue['themes_' + escapedKey] =
            [_resolveTheme(rootPath, indicoClientPath, prefix + themes[k].stylesheet)];

        if (themes[k].print_stylesheet) {
            returnValue['themes_' + escapedKey + '.print'] =
                [_resolveTheme(rootPath, indicoClientPath, prefix + themes[k].print_stylesheet)];
        }
        return returnValue;
    }));
}

export function generateAssetPath(config, virtualVersion = false) {
    // /css/whatever.css => /css/whatever__v123abcdef.css
    return (file) => {
        const relPath = path.relative(config.build.staticPath, file);
        const {dir, name, ext} = path.parse(relPath);
        const h = createHash('md5');
        h.update(fs.readFileSync(file));
        const hash = h.digest('hex').slice(0, 8);
        // the "virtual version" is used for files that are loaded as-is from the
        // static folder and thus do not actually get the hash in the physical
        // file name. it is distinct from the normal version style so a rule on
        // the web server can strip that version segment
        const fileName = virtualVersion ? `${name}__v${hash}${ext}` : `${name}.${hash}${ext}`;
        // .. -> _, like file-loader does
        return dir.replace(/\.\./g, '_') + path.sep + fileName;
    };
}

export function webpackDefaults(env, config) {
    const currentEnv = (env ? env.NODE_ENV : null) || 'development';
    const nodeModules = [path.join(config.build.indicoSourcePath || path.resolve(config.build.rootPath, '..'),
                                   'node_modules')];

    if (config.isPlugin) {
        // add plugin's node_modules in addition to the core's
        nodeModules.push(path.resolve(config.build.rootPath, '../node_modules'));
    }

    const _cssLoaderOptions = {
        root: config.indico ? config.indico.build.staticPath : config.build.staticPath,
        url: true
    };

    const scssIncludePath = path.join((config.isPlugin ?
        path.resolve(config.build.indicoSourcePath, './indico/web/client') :
        path.join(config.build.clientPath)),
                                      'styles');

    function getDevtoolFilename(info) {
        const root = path.resolve(config.indico ? config.indico.build.rootPath : config.build.rootPath, '..');
        return path.relative(root, info.absoluteResourcePath);
    }
    const indicoClientPath = config.isPlugin ? config.indico.build.clientPath : config.build.clientPath;

    return {
        devtool: 'source-map',
        context: config.build.clientPath,
        output: {
            path: config.build.distPath,
            filename: "js/[name].[chunkhash:8].bundle.js",
            publicPath: config.build.distURL,
            devtoolModuleFilenameTemplate: (info) => `webpack:///${getDevtoolFilename(info)}`,
            devtoolFallbackModuleFilenameTemplate: (info) => `webpack:///${getDevtoolFilename(info)}?${info.hash}`,
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: 'babel-loader',
                    exclude: /node_modules/
                },
                {
                    test: /\.css$/,
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: {
                            loader: 'css-loader',
                            options: _cssLoaderOptions
                        }
                    })
                },
                {
                    test: /\.scss$/,
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: [{
                            loader: 'css-loader',
                            options: {
                                root: config.indico ? config.indico.build.staticPath : config.build.staticPath,
                                sourceMap: true,
                                url: !config.isPlugin, // FIXME: true breaks plugins, false breaks /indico/ in core
                            }
                        }, {
                            loader: 'postcss-loader',
                            options: {
                                sourceMap: true,
                                config: {
                                    path: path.join(config.indico ? config.indico.build.rootPath :
                                                                    config.build.rootPath,
                                                    'postcss.config.js'),
                                    ctx: {
                                        urlnamespaces: {
                                            namespacePaths: (name) => {
                                                return path.join(config.indico.build.staticURL, 'static/plugins', name);
                                            }
                                        }
                                    }
                                }
                            }
                        }, {
                            loader: 'sass-loader',
                            options: {
                                sourceMap: true,
                                includePaths: [scssIncludePath],
                                outputStyle: 'compact',
                                importer: importOnce,
                            }
                        }],
                    })
                }
            ]
        },
        plugins: [
            new ManifestPlugin({
                fileName: 'manifest.json',
                publicPath: config.build.distURL
            }),
            // Do not load moment locales (we'll load them explicitly)
            new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
            new ExtractTextPlugin({
                filename: 'css/[name].[md5:contenthash:hex:8].css'
            }),
            new webpack.EnvironmentPlugin({
                NODE_ENV: currentEnv
            }),
            new ProgressBarPlugin({
                format: chalk.cyan('Code being sent to the moon and back \u{1f680} \u{1f311}') + '  [:bar] ' +
                    chalk.green.bold(':percent') + ' (:elapsed seconds)'
            })
        ],
        resolve: {
            alias: [
                {name: 'indico', alias: path.join(indicoClientPath, 'js/')}
            ]
        },
        resolveLoader: {
            modules: nodeModules
        },
        stats: {
            assets: false,
            children: false,
            modules: false,
            chunks: true,
            chunkModules: false,
            chunkOrigins: false,
            chunksSort: 'name'
        },
        mode: currentEnv,
        optimization: {
            splitChunks: {
                cacheGroups: {
                    common: {
                        name: "common",
                        chunks: "initial",
                        minChunks: 2
                    }
                }
            }
        }
    };
}

export function indicoStaticLoader(config) {
    return {
        test: /\/static\/(images|fonts)\/.*\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/,
        use: {
            loader: 'file-loader',
            options: {
                name: generateAssetPath(config, true),
                context: config.build.staticPath,
                emitFile: false,
                publicPath: config.build.staticURL,
            }
        }
    };
}
<commit_msg>Keep selectize from loading jQuery a second time<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2017 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

import {createHash} from 'crypto';
import chalk from 'chalk';
import fs from 'fs';
import path from 'path';

import webpack from 'webpack';

import ExtractTextPlugin from 'extract-text-webpack-plugin';
import ManifestPlugin from 'webpack-manifest-plugin';
import ProgressBarPlugin from 'progress-bar-webpack-plugin';
import importOnce from 'node-sass-import-once';

function _resolveTheme(rootPath, indicoClientPath, filePath) {
    const indicoRelativePath = path.resolve(indicoClientPath, filePath);

    if (indicoClientPath && !fs.existsSync(path.resolve(rootPath, filePath)) &&
            fs.existsSync(indicoRelativePath)) {
        return path.resolve(indicoClientPath, filePath);
    }

    return path.resolve(rootPath, filePath);
}

export function getThemeEntryPoints(config, prefix) {
    const themes = config.themes;
    const indicoClientPath = path.join(config.isPlugin ? config.indico.build.clientPath : config.build.clientPath,
                                       'styles');
    const rootPath = path.join(config.build.rootPath);

    return Object.assign(...Object.keys(themes).map((k) => {
        const returnValue = {};
        const escapedKey = k.replace('-', '_');

        returnValue['themes_' + escapedKey] =
            [_resolveTheme(rootPath, indicoClientPath, prefix + themes[k].stylesheet)];

        if (themes[k].print_stylesheet) {
            returnValue['themes_' + escapedKey + '.print'] =
                [_resolveTheme(rootPath, indicoClientPath, prefix + themes[k].print_stylesheet)];
        }
        return returnValue;
    }));
}

export function generateAssetPath(config, virtualVersion = false) {
    // /css/whatever.css => /css/whatever__v123abcdef.css
    return (file) => {
        const relPath = path.relative(config.build.staticPath, file);
        const {dir, name, ext} = path.parse(relPath);
        const h = createHash('md5');
        h.update(fs.readFileSync(file));
        const hash = h.digest('hex').slice(0, 8);
        // the "virtual version" is used for files that are loaded as-is from the
        // static folder and thus do not actually get the hash in the physical
        // file name. it is distinct from the normal version style so a rule on
        // the web server can strip that version segment
        const fileName = virtualVersion ? `${name}__v${hash}${ext}` : `${name}.${hash}${ext}`;
        // .. -> _, like file-loader does
        return dir.replace(/\.\./g, '_') + path.sep + fileName;
    };
}

export function webpackDefaults(env, config) {
    const currentEnv = (env ? env.NODE_ENV : null) || 'development';
    const nodeModules = [path.join(config.build.indicoSourcePath || path.resolve(config.build.rootPath, '..'),
                                   'node_modules')];

    if (config.isPlugin) {
        // add plugin's node_modules in addition to the core's
        nodeModules.push(path.resolve(config.build.rootPath, '../node_modules'));
    }

    const _cssLoaderOptions = {
        root: config.indico ? config.indico.build.staticPath : config.build.staticPath,
        url: true
    };

    const scssIncludePath = path.join((config.isPlugin ?
        path.resolve(config.build.indicoSourcePath, './indico/web/client') :
        path.join(config.build.clientPath)),
                                      'styles');

    function getDevtoolFilename(info) {
        const root = path.resolve(config.indico ? config.indico.build.rootPath : config.build.rootPath, '..');
        return path.relative(root, info.absoluteResourcePath);
    }
    const indicoClientPath = config.isPlugin ? config.indico.build.clientPath : config.build.clientPath;

    return {
        devtool: 'source-map',
        context: config.build.clientPath,
        output: {
            path: config.build.distPath,
            filename: "js/[name].[chunkhash:8].bundle.js",
            publicPath: config.build.distURL,
            devtoolModuleFilenameTemplate: (info) => `webpack:///${getDevtoolFilename(info)}`,
            devtoolFallbackModuleFilenameTemplate: (info) => `webpack:///${getDevtoolFilename(info)}?${info.hash}`,
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: 'babel-loader',
                    exclude: /node_modules/
                },
                {
                    test: /\.css$/,
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: {
                            loader: 'css-loader',
                            options: _cssLoaderOptions
                        }
                    })
                },
                {
                    test: /\.scss$/,
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: [{
                            loader: 'css-loader',
                            options: {
                                root: config.indico ? config.indico.build.staticPath : config.build.staticPath,
                                sourceMap: true,
                                url: !config.isPlugin, // FIXME: true breaks plugins, false breaks /indico/ in core
                            }
                        }, {
                            loader: 'postcss-loader',
                            options: {
                                sourceMap: true,
                                config: {
                                    path: path.join(config.indico ? config.indico.build.rootPath :
                                                                    config.build.rootPath,
                                                    'postcss.config.js'),
                                    ctx: {
                                        urlnamespaces: {
                                            namespacePaths: (name) => {
                                                return path.join(config.indico.build.staticURL, 'static/plugins', name);
                                            }
                                        }
                                    }
                                }
                            }
                        }, {
                            loader: 'sass-loader',
                            options: {
                                sourceMap: true,
                                includePaths: [scssIncludePath],
                                outputStyle: 'compact',
                                importer: importOnce,
                            }
                        }],
                    })
                }
            ]
        },
        plugins: [
            new ManifestPlugin({
                fileName: 'manifest.json',
                publicPath: config.build.distURL
            }),
            // Do not load moment locales (we'll load them explicitly)
            new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
            new ExtractTextPlugin({
                filename: 'css/[name].[md5:contenthash:hex:8].css'
            }),
            new webpack.EnvironmentPlugin({
                NODE_ENV: currentEnv
            }),
            new ProgressBarPlugin({
                format: chalk.cyan('Code being sent to the moon and back \u{1f680} \u{1f311}') + '  [:bar] ' +
                    chalk.green.bold(':percent') + ' (:elapsed seconds)'
            })
        ],
        resolve: {
            alias: [
                {name: 'indico', alias: path.join(indicoClientPath, 'js/')}
            ]
        },
        resolveLoader: {
            modules: nodeModules
        },
        externals: (context, request, callback) => {
            // tell webpack to make selectize use window.jQuery (and not load it again)
            if (/^jquery$/.test(request) && /selectize/.test(context)) {
                return callback(null, 'jQuery')
            }
            return callback();
        },
        stats: {
            assets: false,
            children: false,
            modules: false,
            chunks: true,
            chunkModules: false,
            chunkOrigins: false,
            chunksSort: 'name'
        },
        mode: currentEnv,
        optimization: {
            splitChunks: {
                cacheGroups: {
                    common: {
                        name: "common",
                        chunks: "initial",
                        minChunks: 2
                    }
                }
            }
        }
    };
}

export function indicoStaticLoader(config) {
    return {
        test: /\/static\/(images|fonts)\/.*\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/,
        use: {
            loader: 'file-loader',
            options: {
                name: generateAssetPath(config, true),
                context: config.build.staticPath,
                emitFile: false,
                publicPath: config.build.staticURL,
            }
        }
    };
}
<|endoftext|>


<commit_before>
my_ext = {
    whoami: "GPAC-GUI-Extension",
    name: "",
    icon: "H2B2VS.png",
    author: "JeanLF",
    description: "H2B2VS Preferences",
    url: "http://h2b2vs.epfl.ch/",
    execjs: ["h2b2vs.js"],
    autostart: true,
    config_id: "H2B2VS",
    requires_gl: false,
    version_major: 1,
    version_minor: 0
};

<commit_msg>disable auto load of h2b2vs ext<commit_after>
my_ext = {
    whoami: "GPAC-GUI-Extension",
    name: "",
    icon: "H2B2VS.png",
    author: "JeanLF",
    description: "H2B2VS Preferences",
    url: "http://h2b2vs.epfl.ch/",
    execjs: ["h2b2vs.js"],
    autostart: false,
    config_id: "H2B2VS",
    requires_gl: false,
    version_major: 1,
    version_minor: 0
};

<|endoftext|>


<commit_before>'use strict';

/* global sanitizeText: false */

/**
 * @ngdoc filter
 * @name linky
 * @kind function
 *
 * @description
 * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
 * plain email address links.
 *
 * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
 *
 * @param {string} text Input text.
 * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
 * @param {object|function(url)} [attributes] Add custom attributes to the link element.
 *
 *    Can be one of:
 *
 *    - `object`: A map of attributes
 *    - `function`: Takes the url as a parameter and returns a map of attributes
 *
 *    If the map of attributes contains a value for `target`, it overrides the value of
 *    the target parameter.
 *
 * @returns {string} Html-linkified text.
 *
 * @usage

 *
 * @example
   <example module="linkyExample" deps="angular-sanitize.js">
     <file name="index.html">

       Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>

           Filter
           Source
           Rendered

           linky filter

<div ng-bind-html="snippet | linky">
</div>

          linky target

<div ng-bind-html="snippetWithSingleURL | linky:'_blank'">
</div>

          linky custom attributes

<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}">
</div>

           no filter

<div ng-bind="snippet">
</div>

     </file>
     <file name="protractor.js" type="protractor">
       it('should linkify the snippet with urls', function() {
         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
             toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
                  'another@somewhere.org, and one more: ftp://127.0.0.1/.');
         expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
       });

       it('should not linkify snippet without the linky filter', function() {
         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
             toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
                  'another@somewhere.org, and one more: ftp://127.0.0.1/.');
         expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
       });

       it('should update', function() {
         element(by.model('snippet')).clear();
         element(by.model('snippet')).sendKeys('new http://link.');
         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
             toBe('new http://link.');
         expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
             .toBe('new http://link.');
       });

       it('should work with the target property', function() {
        expect(element(by.id('linky-target')).
            element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
            toBe('http://angularjs.org/');
        expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
       });

       it('should optionally add custom attributes', function() {
        expect(element(by.id('linky-custom-attributes')).
            element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
            toBe('http://angularjs.org/');
        expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
       });
     </file>
   </example>
 */
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
  var LINKY_URL_REGEXP =
        /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
      MAILTO_REGEXP = /^mailto:/i;

  return function(text, target, attributes) {
    if (!text) return text;
    var match;
    var raw = text;
    var html = [];
    var url;
    var i;
    while ((match = raw.match(LINKY_URL_REGEXP))) {
      // We can not end in these as they are sometimes found at the end of the sentence
      url = match[0];
      // if we did not match ftp/http/www/mailto then assume mailto
      if (!match[2] && !match[4]) {
        url = (match[3] ? 'http://' : 'mailto:') + url;
      }
      i = match.index;
      addText(raw.substr(0, i));
      addLink(url, match[0].replace(MAILTO_REGEXP, ''));
      raw = raw.substring(i + match[0].length);
    }
    addText(raw);
    return $sanitize(html.join(''));

    function addText(text) {
      if (!text) {
        return;
      }
      html.push(sanitizeText(text));
    }

    function addLink(url, text) {
      var key;
      html.push('<a ');
      if (angular.isFunction(attributes)) {
        attributes = attributes(url);
      }
      if (angular.isObject(attributes)) {
        for (key in attributes) {
          html.push(key + '="' + attributes[key] + '" ');
        }
      } else {
        attributes = {};
      }
      if (angular.isDefined(target) && !('target' in attributes)) {
        html.push('target="',
                  target,
                  '" ');
      }
      html.push('href="',
                url.replace(/"/g, '"'),
                '">');
      addText(text);
      html.push('');
    }
  };
}]);
<commit_msg>docs(linky): mention sanitization, improve formatting<commit_after>'use strict';

/* global sanitizeText: false */

/**
 * @ngdoc filter
 * @name linky
 * @kind function
 *
 * @description
 * Finds links in text input and turns them into html links. Supports `http/https/ftp/mailto` and
 * plain email address links.
 *
 * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
 *
 * @param {string} text Input text.
 * @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in.
 * @param {object|function(url)} [attributes] Add custom attributes to the link element.
 *
 *    Can be one of:
 *
 *    - `object`: A map of attributes
 *    - `function`: Takes the url as a parameter and returns a map of attributes
 *
 *    If the map of attributes contains a value for `target`, it overrides the value of
 *    the target parameter.
 *
 *
 * @returns {string} Html-linkified and {@link $sanitize sanitized} text.
 *
 * @usage

 *
 * @example
   <example module="linkyExample" deps="angular-sanitize.js">
     <file name="index.html">

       Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>

           Filter
           Source
           Rendered

           linky filter

<div ng-bind-html="snippet | linky">
</div>

          linky target

<div ng-bind-html="snippetWithSingleURL | linky:'_blank'">
</div>

          linky custom attributes

<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}">
</div>

           no filter

<div ng-bind="snippet">
</div>

     </file>
     <file name="script.js">
       angular.module('linkyExample', ['ngSanitize'])
         .controller('ExampleController', ['$scope', function($scope) {
           $scope.snippet =
             'Pretty text with some links:\n'+
             'http://angularjs.org/,\n'+
             'mailto:us@somewhere.org,\n'+
             'another@somewhere.org,\n'+
             'and one more: ftp://127.0.0.1/.';
           $scope.snippetWithSingleURL = 'http://angularjs.org/';
         }]);
     </file>
     <file name="protractor.js" type="protractor">
       it('should linkify the snippet with urls', function() {
         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
             toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
                  'another@somewhere.org, and one more: ftp://127.0.0.1/.');
         expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
       });

       it('should not linkify snippet without the linky filter', function() {
         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
             toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
                  'another@somewhere.org, and one more: ftp://127.0.0.1/.');
         expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
       });

       it('should update', function() {
         element(by.model('snippet')).clear();
         element(by.model('snippet')).sendKeys('new http://link.');
         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
             toBe('new http://link.');
         expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
             .toBe('new http://link.');
       });

       it('should work with the target property', function() {
        expect(element(by.id('linky-target')).
            element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
            toBe('http://angularjs.org/');
        expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
       });

       it('should optionally add custom attributes', function() {
        expect(element(by.id('linky-custom-attributes')).
            element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
            toBe('http://angularjs.org/');
        expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
       });
     </file>
   </example>
 */
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
  var LINKY_URL_REGEXP =
        /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
      MAILTO_REGEXP = /^mailto:/i;

  return function(text, target, attributes) {
    if (!text) return text;
    var match;
    var raw = text;
    var html = [];
    var url;
    var i;
    while ((match = raw.match(LINKY_URL_REGEXP))) {
      // We can not end in these as they are sometimes found at the end of the sentence
      url = match[0];
      // if we did not match ftp/http/www/mailto then assume mailto
      if (!match[2] && !match[4]) {
        url = (match[3] ? 'http://' : 'mailto:') + url;
      }
      i = match.index;
      addText(raw.substr(0, i));
      addLink(url, match[0].replace(MAILTO_REGEXP, ''));
      raw = raw.substring(i + match[0].length);
    }
    addText(raw);
    return $sanitize(html.join(''));

    function addText(text) {
      if (!text) {
        return;
      }
      html.push(sanitizeText(text));
    }

    function addLink(url, text) {
      var key;
      html.push('<a ');
      if (angular.isFunction(attributes)) {
        attributes = attributes(url);
      }
      if (angular.isObject(attributes)) {
        for (key in attributes) {
          html.push(key + '="' + attributes[key] + '" ');
        }
      } else {
        attributes = {};
      }
      if (angular.isDefined(target) && !('target' in attributes)) {
        html.push('target="',
                  target,
                  '" ');
      }
      html.push('href="',
                url.replace(/"/g, '"'),
                '">');
      addText(text);
      html.push('');
    }
  };
}]);
<|endoftext|>


<commit_before>//Canvas stuff
var canvas = {};
canvas.element = $("#canvas")[0];
canvas.context = canvas.element.getContext("2d");
canvas.width = $("#canvas").width();
canvas.height = $("#canvas").height();

//Debug stuff
var DEBUG_MODE = false;

//User stuff
var myUserID = 0;
var myUserName;

//Defaults
var GOINSTANT_APP_URL = 'https://goinstant.net/NinjaOtter/NodeKnockout';
var INITIAL_SNAKE_LENGTH = 5;
var INITIAL_SCORE = 0;
var BLOCK_SIZE = 10;

// food
var food = {
  color: 'black'
};

// snakes
var snakes = {};
var snakeKey;

function initializeSnake(userName) {
  snakes[userName] = {
    blocks: [],
    color: '',
    currentScore: 0,
    highScore: 0,
    length: INITIAL_SNAKE_LENGTH,
    direction: ''
  };
  for(var x = 0; x < snakes[myUserName].length; x++) {
    snakes[myUserName].blocks[x] = { x: 0, y: 0 };
  }
}
function initializeGame() {

  goinstant.connect(GOINSTANT_APP_URL, function (err, platform, lobby) {
    if (err) {
      throw err;
    }

    snakeKey = lobby.key('/snakes');
    food.key = lobby.key('/food');

    getUsername();
    initializeSnake(myUserName);
    spawnSnake(myUserName);

    // Setup GoInstant widgets
    var userList = new goinstant.widgets.UserList({
      room: lobby,
      collapsed: false,
      position: 'right'
    });
    userList.initialize();

    // randomly select a color for the user
    var userColors = new goinstant.widgets.UserColors({ room: lobby });
    userColors.choose(function(err, color) {
      snakes[myUserName].color = color;
    });

    var foodListener = function(val) {
      food = { x: val.x, y: val.y };
    };

    food.key.on('set', { local: true, listener: foodListener });

    food.key.get(function(err, value, context) {
      if (value) {
        food = {
          x: value.x,
          y: value.y
        };
      } else {
        spawnFood();
      }

      snakeKey.key("/" + myUserName).set(snakes[myUserName], function(err) {
        if (err) {
          throw err;
        }
      });

      var snakeListener = function(val, context) {
        var username = context.key.substr('/snakes/'.length);
        snakes[username] = context.value;
      };

      snakeKey.on('set', { bubble:true, listener: snakeListener });

      snakeKey.get(function(err, value, context) {
        if (err) {
          throw err;
        }
        snakes = value;

        // Change the user's name
        lobby.user(function(err, user, userKey) {
          if (err) throw err;

          var displayNameKey = userKey.key('displayName');
          displayNameKey.set(myUserName, function(err) {
            if (err) throw err;

            var publishOpts = {
              room: lobby,
              type: 'success',
              message: myUserName + ' has joined.',
              displayToSelf: true
            };

            // Get all notifications of users joining

            var notifications = new goinstant.widgets.Notifications();
            notifications.subscribe(lobby);

            // publish a notification of the new user
            notifications.publish(publishOpts, function(err) {
              if (err) {
                throw err;
              }

              if(typeof gameTimer != "undefined") {
                clearInterval(gameTimer);
              }
              gameTimer = setInterval(gameTick, 60);
            });
          });
        });
      });
    });
  });
}

function gameTick() {
  //Draw the canvas all the time to avoid trails.
  drawCanvas();

  //Move snakes & detect collisions
  _.each(_.keys(snakes), function(username) {
    var currentSnake = snakes[username];

    drawSnake(currentSnake);
    incrementSnakePosition(username);

    // only with our snake
    if(username == myUserName) {

      if (checkWallCollision(username)) {
        spawnSnake(username);
      }

      // This will prevent all other players from respawning the food
      if (checkFoodCollision(username)) {

        increaseSnakeLength(username);
        spawnFood();
        currentSnake.currentScore++;
        updateHighScore(username);
      }
    }
  });

  drawFood();
}

function incrementSnakePosition(username) {
  var currentSnake = snakes[username];
  switch(currentSnake.direction) {
    case 'up':
      currentSnake.blocks[0].y--;
      break;
    case 'down':
      currentSnake.blocks[0].y++;
      break;
    case 'left':
      currentSnake.blocks[0].x--;
      break;
    case 'right':
      currentSnake.blocks[0].x++;
      break;
  }
}

function increaseSnakeLength(username) {
  var currentSnake = snakes[username];
  currentSnake.length++;

  currentSnake.blocks[currentSnake.length-1] = {
    x: currentSnake.blocks[currentSnake.length-2].x,
    y: currentSnake.blocks[currentSnake.length-2].y
  };

  switch(currentSnake.direction) {
    case 'up':
      currentSnake.blocks[currentSnake.length-1].y--;
      break;
    case 'down':
      currentSnake.blocks[currentSnake.length-1].y++;
      break;
    case 'left':
      currentSnake.blocks[currentSnake.length-1].x--;
      break;
    case 'right':
      currentSnake.blocks[currentSnake.length-1].x++;
      break;
    default:
      throw new Error("invalid snake direction");
  }
}

function drawFood() {
  canvas.context.fillStyle = food.color;
  canvas.context.fillRect((food.x*BLOCK_SIZE), (food.y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);
}

function drawSnake(currentSnake) {
  canvas.context.fillStyle = currentSnake.color;
  for(var x = currentSnake.length-1; x >= 0; x--) {
    canvas.context.fillRect((currentSnake.blocks[x].x*BLOCK_SIZE), (currentSnake.blocks[x].y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);

    //Inherit past position, only on our snake
    if(x > 0) {
      currentSnake.blocks[x].x = currentSnake.blocks[x-1].x;
      currentSnake.blocks[x].y = currentSnake.blocks[x-1].y;
    }
  }
}

// this will get rid of other snakes from lost connections, etc.
function checkWallCollision(username) {
  if (currentSnake.blocks[0].y < -1 ||
       currentSnake.blocks[0].y > (canvas.height/BLOCK_SIZE) ||
       currentSnake.blocks[0].x < -1 ||
       currentSnake.blocks[0].x > (canvas.width/BLOCK_SIZE)) {
    return true;
  }
  return false;
}

function checkFoodCollision(username) {
  var currentSnake = snakes[username];
  if(currentSnake.blocks[0].y == food.y && currentSnake.blocks[0].x == food.x) {
    return true;
  }
  return false;
}

function updateHighScore(userName) {
  var currentSnake = snakes[snakeUsername];
  if(currentSnake.highScore < currentSnake.currentScore) {
    currentSnake.highScore = currentSnake.currentScore;
  }
}

function spawnSnake(snakeUsername) {
  //spawn a new instance of the snake & destroy the old
  var currentSnake = snakes[snakeUsername];

  //Set length to default
  currentSnake.length = INITIAL_SNAKE_LENGTH;

  //Did the user hit a high score?
  updateHighScore(snakeUsername);

  //Reset score
  currentSnake.currentScore = INTIAL_SCORE;

  //Find new spawn location
  var newPos = {
    x: Math.round(Math.random()*(canvas.width-BLOCK_SIZE)/BLOCK_SIZE),
    y: Math.round(Math.random()*(canvas.height-BLOCK_SIZE)/BLOCK_SIZE)
  };

  //Set new direction
  switch(Math.round(Math.random()*3)) {
    case 0:
      currentSnake.direction = 'up';
      break;
    case 1:
      currentSnake.direction = 'down';
      break;
    case 2:
      currentSnake.direction = 'left';
      break;
    case 3:
      currentSnake.direction = 'right';
      break;
  }

  //Setup new snake blocks
  currentSnake.blocks[0].x = newPos.x;
  currentSnake.blocks[0].y = newPos.y;

  for(var x = 1; x < currentSnake.length; x++) {
    currentSnake.blocks[x].x = currentSnake.blocks[x-1].x;
    currentSnake.blocks[x].y = currentSnake.blocks[x-1].y;

    switch(currentSnake.direction){
      case 'up':
        currentSnake.blocks[x].y--;
        break;
      case 'down':
        currentSnake.blocks[x].y++;
        break;
      case 'right':
        currentSnake.blocks[x].x--;
        break;
      case 'left':
        currentSnake.blocks[x].x++;
        break;
      default:
        throw new Error("invalid snake direction");
    }
  }

  this.snakeKey.key("/" + snakeUsername).set(currentSnake, function(err) {
    if(err) throw err;
  });
}

function drawDebugCanvas() {
  for(var x=0; x<(canvas.width/BLOCK_SIZE); x++) {
    for(var y=0; y<(canvas.height/BLOCK_SIZE); y++) {
      canvas.context.fillStyle = "white";
      canvas.context.fillRect((x*BLOCK_SIZE), (y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);
      canvas.context.strokeStyle = "black";
      canvas.context.strokeRect((x*BLOCK_SIZE), (y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);
    }
  }
}

function drawCanvas() {
  if (DEBUG_MODE) {
    drawDebugCanvas();
  } else {
    canvas.context.fillStyle = "white";
    canvas.context.fillRect(0, 0, canvas.width, canvas.height);
    canvas.context.strokeStyle = "black";
    canvas.context.strokeRect(0, 0, canvas.width, canvas.height);
  }
}

function spawnFood() {
  food = {
    x: Math.round(Math.random()*((canvas.width-200)-BLOCK_SIZE)/BLOCK_SIZE),
    y: Math.round(Math.random()*(canvas.height-BLOCK_SIZE)/BLOCK_SIZE),
  };
  food.key.set(food, function(err) {
    if(err) {
      throw err;
    }
  });
}

// If the user is unknown to us, try to get a username
function getUsername() {
  myUserName = sessionStorage.getItem('gi_username');
  if (myUserName) {
    return;
  }

  myUserName = prompt('What is your name?', 'Guest');
  if (!myUserName){
    myUserName = 'Guest';
  }
  sessionStorage.setItem('gi_username', myUserName);
}

$(document).ready(function () {
  // Init GoInstant
  initializeGame();
});

$(window).on('beforeunload', function(){
  snakeKey.key("/" + myUserName).remove(function(err, value, context) {
    if (err) {
      throw err;
    }
  });
});

// Keyboard Controls
$(document).keydown(function(e){
  var key = e.which;
  var currentSnake = snakes[myUserName];
  if(key == "37" && currentSnake.direction != "right") {
    currentSnake.direction = "left";
  } else if(key == "38" && currentSnake.direction != "down") {
    currentSnake.direction = "up";
  } else if(key == "39" && currentSnake.direction != "left") {
    currentSnake.direction = "right";
  } else if(key == "40" && currentSnake.direction != "up") {
    currentSnake.direction = "down";
  }
  console.log("CurrentDirection:",snakes[myUserName].direction);

  snakeKey.key("/" + myUserName).set(currentSnake, function(err) {
    if(err) {
      throw err;
    }
  });
});

<commit_msg>async improvements<commit_after>//Canvas stuff
var canvas = {};
canvas.element = $("#canvas")[0];
canvas.context = canvas.element.getContext("2d");
canvas.width = $("#canvas").width();
canvas.height = $("#canvas").height();

//Debug stuff
var DEBUG_MODE = false;

//User stuff
var myUserID = 0;
var myUserName;

//Defaults
var GOINSTANT_APP_URL = 'https://goinstant.net/NinjaOtter/NodeKnockout';
var INITIAL_SNAKE_LENGTH = 5;
var INITIAL_SCORE = 0;
var BLOCK_SIZE = 10;

// food
var food = {
  color: 'black'
};

// snakes
var snakes = {};
var snakeKey;

var lobby;

function initializeSnake(cb) {
  snakes[myUserName] = {
    blocks: [],
    color: '',
    currentScore: 0,
    highScore: 0,
    length: INITIAL_SNAKE_LENGTH,
    direction: ''
  };
  for(var x = 0; x < snakes[myUserName].length; x++) {
    snakes[myUserName].blocks[x] = { x: 0, y: 0 };
  }
  var snakeListener = function(val, context) {
    var username = context.key.substr('/snakes/'.length);
    snakes[username] = context.value;
  };
  snakeKey.on('set', { bubble:true, listener: snakeListener });
  snakeKey.key("/" + myUserName).set(snakes[myUserName], function(err) {
    if (err) {
      throw err;
    }
    snakeKey.get(function(err, value, context) {
      if (err) {
        throw err;
      }
      snakes = value;
      spawnSnake(myUserName);
      return cb();
    });
  });
}
function initializeGame() {

  goinstant.connect(GOINSTANT_APP_URL, function (err, platform, room) {
    if (err) {
      throw err;
    }
    lobby = room;

    snakeKey = lobby.key('/snakes');
    food.key = lobby.key('/food');

    async.series([
      initializeFood(next),
      initializeSnake(next),
      initializeUser(next),
      initializeNotifications(next),
      initializeGameLoop(next)
    ], function(err) {
      if (err) {
        throw err;
      }
    });
  });
}

// If the user is unknown to us, try to get a username
function initializeUsername(cb) {
  myUserName = sessionStorage.getItem('gi_username');
  if (!myUserName) {
    myUserName = prompt('What is your name?', 'Guest');
    if (!myUserName){
      myUserName = 'Guest';
    }
    sessionStorage.setItem('gi_username', myUserName);
  }
  var userList = new goinstant.widgets.UserList({
    room: lobby,
    collapsed: false,
    position: 'right'
  });
  lobby.user(function(err, user, userKey) {
    if (err) {
      throw err;
    }

    var displayNameKey = userKey.key('displayName');
    displayNameKey.set(myUserName, function(err) {
      if (err) {
        throw err;
      }
      userList.initialize(function(err) {
        // randomly select a color for the user
        var userColors = new goinstant.widgets.UserColors({ room: lobby });
        userColors.choose(function(err, color) {
          snakes[myUserName].color = color;
        });
      });
    });
  });
}

function initializeNotifications(cb) {
  var notifications = new goinstant.widgets.Notifications();

  // Get all notifications of users joining
  notifications.subscribe(lobby);

  var msg = myUserName + ' has joined.';

  // publish a notification of the new user
  notifications.publish({
    room: lobby,
    type: 'success',
    message: msg,
    displayToSelf: true
  }, function(err) {
    if (err) {
      throw err;
    }
    return cb();
  });
}

function initializeGameLoop() {
  if(typeof gameTimer != "undefined") {
    clearInterval(gameTimer);
  }
  gameTimer = setInterval(gameTick, 60);
  return cb();
}

function initializeFood(cb) {
  var foodListener = function(val) {
    food = { x: val.x, y: val.y };
  };

  food.key.on('set', { local: true, listener: foodListener });
  food.key.get(function(err, value, context) {
    if (value) {
      food = {
        x: value.x,
        y: value.y
      };
      return cb();
    }
    spawnFood(cb);
  });
}

function gameTick() {
  //Draw the canvas all the time to avoid trails.
  drawCanvas();

  //Move snakes & detect collisions
  _.each(_.keys(snakes), function(username) {
    var currentSnake = snakes[username];

    drawSnake(currentSnake);
    incrementSnakePosition(username);

    // only with our snake
    if(username == myUserName) {

      if (checkWallCollision(username)) {
        spawnSnake(username);
      }

      // This will prevent all other players from respawning the food
      if (checkFoodCollision(username)) {

        increaseSnakeLength(username);
        spawnFood();
        currentSnake.currentScore++;
        updateHighScore(username);
      }
    }
  });

  drawFood();
}

function incrementSnakePosition(username) {
  var currentSnake = snakes[username];
  switch(currentSnake.direction) {
    case 'up':
      currentSnake.blocks[0].y--;
      break;
    case 'down':
      currentSnake.blocks[0].y++;
      break;
    case 'left':
      currentSnake.blocks[0].x--;
      break;
    case 'right':
      currentSnake.blocks[0].x++;
      break;
  }
}

function increaseSnakeLength(username) {
  var currentSnake = snakes[username];
  currentSnake.length++;

  currentSnake.blocks[currentSnake.length-1] = {
    x: currentSnake.blocks[currentSnake.length-2].x,
    y: currentSnake.blocks[currentSnake.length-2].y
  };

  switch(currentSnake.direction) {
    case 'up':
      currentSnake.blocks[currentSnake.length-1].y--;
      break;
    case 'down':
      currentSnake.blocks[currentSnake.length-1].y++;
      break;
    case 'left':
      currentSnake.blocks[currentSnake.length-1].x--;
      break;
    case 'right':
      currentSnake.blocks[currentSnake.length-1].x++;
      break;
    default:
      throw new Error("invalid snake direction");
  }
}

function drawFood() {
  canvas.context.fillStyle = food.color;
  canvas.context.fillRect((food.x*BLOCK_SIZE), (food.y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);
}

function drawSnake(currentSnake) {
  canvas.context.fillStyle = currentSnake.color;
  for(var x = currentSnake.length-1; x >= 0; x--) {
    canvas.context.fillRect((currentSnake.blocks[x].x*BLOCK_SIZE), (currentSnake.blocks[x].y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);

    //Inherit past position, only on our snake
    if(x > 0) {
      currentSnake.blocks[x].x = currentSnake.blocks[x-1].x;
      currentSnake.blocks[x].y = currentSnake.blocks[x-1].y;
    }
  }
}

// this will get rid of other snakes from lost connections, etc.
function checkWallCollision(username) {
  if (currentSnake.blocks[0].y < -1 ||
       currentSnake.blocks[0].y > (canvas.height/BLOCK_SIZE) ||
       currentSnake.blocks[0].x < -1 ||
       currentSnake.blocks[0].x > (canvas.width/BLOCK_SIZE)) {
    return true;
  }
  return false;
}

function checkFoodCollision(username) {
  var currentSnake = snakes[username];
  if(currentSnake.blocks[0].y == food.y && currentSnake.blocks[0].x == food.x) {
    return true;
  }
  return false;
}

function updateHighScore(userName) {
  var currentSnake = snakes[snakeUsername];
  if(currentSnake.highScore < currentSnake.currentScore) {
    currentSnake.highScore = currentSnake.currentScore;
  }
}

function spawnSnake(snakeUsername) {
  //spawn a new instance of the snake & destroy the old
  var currentSnake = snakes[snakeUsername];

  //Set length to default
  currentSnake.length = INITIAL_SNAKE_LENGTH;

  //Did the user hit a high score?
  updateHighScore(snakeUsername);

  //Reset score
  currentSnake.currentScore = INTIAL_SCORE;

  //Find new spawn location
  var newPos = {
    x: Math.round(Math.random()*(canvas.width-BLOCK_SIZE)/BLOCK_SIZE),
    y: Math.round(Math.random()*(canvas.height-BLOCK_SIZE)/BLOCK_SIZE)
  };

  //Set new direction
  switch(Math.round(Math.random()*3)) {
    case 0:
      currentSnake.direction = 'up';
      break;
    case 1:
      currentSnake.direction = 'down';
      break;
    case 2:
      currentSnake.direction = 'left';
      break;
    case 3:
      currentSnake.direction = 'right';
      break;
  }

  //Setup new snake blocks
  currentSnake.blocks[0].x = newPos.x;
  currentSnake.blocks[0].y = newPos.y;

  for(var x = 1; x < currentSnake.length; x++) {
    currentSnake.blocks[x].x = currentSnake.blocks[x-1].x;
    currentSnake.blocks[x].y = currentSnake.blocks[x-1].y;

    switch(currentSnake.direction){
      case 'up':
        currentSnake.blocks[x].y--;
        break;
      case 'down':
        currentSnake.blocks[x].y++;
        break;
      case 'right':
        currentSnake.blocks[x].x--;
        break;
      case 'left':
        currentSnake.blocks[x].x++;
        break;
      default:
        throw new Error("invalid snake direction");
    }
  }

  this.snakeKey.key("/" + snakeUsername).set(currentSnake, function(err) {
    if(err) throw err;
  });
}

function drawDebugCanvas() {
  for(var x=0; x<(canvas.width/BLOCK_SIZE); x++) {
    for(var y=0; y<(canvas.height/BLOCK_SIZE); y++) {
      canvas.context.fillStyle = "white";
      canvas.context.fillRect((x*BLOCK_SIZE), (y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);
      canvas.context.strokeStyle = "black";
      canvas.context.strokeRect((x*BLOCK_SIZE), (y*BLOCK_SIZE), BLOCK_SIZE, BLOCK_SIZE);
    }
  }
}

function drawCanvas() {
  if (DEBUG_MODE) {
    drawDebugCanvas();
  } else {
    canvas.context.fillStyle = "white";
    canvas.context.fillRect(0, 0, canvas.width, canvas.height);
    canvas.context.strokeStyle = "black";
    canvas.context.strokeRect(0, 0, canvas.width, canvas.height);
  }
}

function spawnFood(cb) {
  food = {
    x: Math.round(Math.random()*((canvas.width-200)-BLOCK_SIZE)/BLOCK_SIZE),
    y: Math.round(Math.random()*(canvas.height-BLOCK_SIZE)/BLOCK_SIZE),
  };
  food.key.set(food, function(err) {
    if(err) {
      throw err;
    }
    return cb();
  });
}

$(document).ready(function () {
  // Init GoInstant
  initializeGame();
});

$(window).on('beforeunload', function(){
  snakeKey.key("/" + myUserName).remove(function(err, value, context) {
    if (err) {
      throw err;
    }
  });
});

// Keyboard Controls
$(document).keydown(function(e){
  var key = e.which;
  var currentSnake = snakes[myUserName];
  if(key == "37" && currentSnake.direction != "right") {
    currentSnake.direction = "left";
  } else if(key == "38" && currentSnake.direction != "down") {
    currentSnake.direction = "up";
  } else if(key == "39" && currentSnake.direction != "left") {
    currentSnake.direction = "right";
  } else if(key == "40" && currentSnake.direction != "up") {
    currentSnake.direction = "down";
  }
  console.log("CurrentDirection:",snakes[myUserName].direction);

  snakeKey.key("/" + myUserName).set(currentSnake, function(err) {
    if(err) {
      throw err;
    }
  });
});

<|endoftext|>


<commit_before>/**
	ru.getlunch.run
	https://github.com/PavelDubrovskiy/ru.getlunch.run.git

	Cordova plugin for GetLunch.
*/

var exec = require('cordova/exec');

module.exports = {
	/**
	 * Start Yandex Navigator
	 *
	 * @param {object} Coords
	 * @param {Function} completeCallback   The callback that is called when open Yandex Navigator
	 * @param {Function} errorCallback      The callback that is called when an error occurred when the program starts.
	 */
	yandexnavi: function(coords, completeCallback, errorCallback) {
		exec(completeCallback, errorCallback, "getlunchRun", "yandexnavi", [JSON.stringify(coords)])
	}
	telcall: function(phone, completeCallback, errorCallback) {
		exec(completeCallback, errorCallback, "getlunchRun", "telcall", [phone])
	}
}
<commit_msg>Updated 15.54 07.04.2016<commit_after>/**
	ru.getlunch.run
	https://github.com/PavelDubrovskiy/ru.getlunch.run.git

	Cordova plugin for GetLunch.
*/

var exec = require('cordova/exec');

module.exports = {
	/**
	 * Start Yandex Navigator
	 *
	 * @param {object} Coords
	 * @param {Function} completeCallback   The callback that is called when open Yandex Navigator
	 * @param {Function} errorCallback      The callback that is called when an error occurred when the program starts.
	 */
	yandexnavi: function(coords, completeCallback, errorCallback) {
		exec(completeCallback, errorCallback, "getlunchRun", "yandexnavi", [JSON.stringify(coords)])
	},
	telcall: function(phone, completeCallback, errorCallback) {
		exec(completeCallback, errorCallback, "getlunchRun", "telcall", [phone])
	}
}
<|endoftext|>


<commit_before>// this class is not really related to a sampleToc but can be used for any TOC

import API from 'src/util/api';
import Versioning from 'src/util/versioning';

let defaultOptions = {
  group: 'all',
  varName: 'sampleToc',
  viewName: 'sample_toc',
  filter: (entry) => !entry.value.hidden,
  sort: (a, b) => {
    if (a.value.modified && a.value.modified > b.value.modified) {
      return -1;
    } else if (
      a.value.modificationDate &&
      a.value.modificationDate > b.value.modificationDate
    ) {
      return -1;
    } else if (a.value.modified && a.value.modified < b.value.modified) {
      return 1;
    } else if (
      a.value.modificationDate &&
      a.value.modificationDate < b.value.modificationDate
    ) {
      return 1;
    } else {
      return 0;
    }
  },
};

class Toc {
  /**
   * Create an object managing the Toc
   * @param {object} [options={}]
   * @param {object} [roc=undefined]
   * @param {string} [options.group='mine'] Group to retrieve products. mine, all of a specific group name
   * @param {string} [options.varName='sampleToc']
   * @param {string} [options.viewName='sample_toc']
   * @param {function} [options.sort] Callback, by default sort by reverse date
   * @param {function} [options.filter] Callback to filter the result
   */
  constructor(roc, options = {}) {
    this.roc = roc;
    this.options = Object.assign({}, defaultOptions, options);
  }

  setFilter(filter) {
    this.options.filter = filter;
    return this.refresh();
  }

  /**
   * Retrieve the toc and put the result in the specified variable
   *
   */
  refresh(options = {}) {
    let {
      group,
      sort,
      filter,
      viewName,
      limit,
      startkey,
      endkey,
      key,
      descending,
    } = Object.assign({}, this.options, options);
    let mine = 0;
    let groups = '';
    group = String(group);
    if (group === 'mine') {
      mine = 1;
    } else if (group !== 'all') {
      groups = group;
    }
    return this.roc
      .query(viewName, {
        groups,
        mine,
        sort,
        filter,
        limit,
        startkey,
        endkey,
        key,
        descending,
        varName: this.options.varName,
      })
      .then((entries) => {
        if (this.options.callback) {
          entries.forEach(this.options.callback);
        }
        return entries;
      });
  }

  async initializeSampleFilter(options = {}) {
    const {
      twigVarName = 'sampleFilterTwig',
      varName = 'sampleFilter',
      cookieName = 'eln-default-sample-filter',
      filter,
      autoRefresh = true,
      listAllGroups = false,
    } = options;

    let groups = [];
    if (listAllGroups) {
      groups = (await this.roc.getGroupsInfo()).map((g) => g.name);
    } else {
      groups = (await this.roc.getGroupMembership()).map((g) => g.name);
    }

    const defaultSampleFilter = {
      group: 'mine',
      startEpoch: 24 * 3600 * 1000 * 31,
      endEpoch: '',
    };
    const sampleFilter = localStorage.getItem(cookieName)
      ? JSON.parse(localStorage.getItem(cookieName))
      : defaultSampleFilter;
    API.createData(varName, sampleFilter);

    this.updateOptions(sampleFilter);

    const sampleFilterTwig = `
Group: <select name="group">
<option value='all'>All</option>
<option value='mine'>Mine</option>
${groups.map((group) => '<option value="' + group + '">' + group + '</option>')}
</select>
Period: <select name="startEpoch">
<option value='${24 * 3600 * 1000 * 31}'>Last month</option>
<option value='${24 * 3600 * 1000 * 91}'>Last 3 months</option>
<option value='${24 * 3600 * 1000 * 182}'>Last 6 months</option>
<option value='${24 * 3600 * 1000 * 365}'>Last year</option>
<option value='${24 * 3600 * 1000 * 730}'>Last 2 years</option>
<option value='${24 * 3600 * 1000 * 1830}'>Last 5 years</option>
<option value=''>Any time</option>
</select>
`;
    API.createData(twigVarName, sampleFilterTwig);

    if (autoRefresh) {
      await this.refresh(filter);
    }
    let mainData = Versioning.getData();
    mainData.onChange((evt) => {
      if (evt.jpath[0] === varName) {
        const currentSampleFilter = API.getData(varName).resurrect();
        localStorage.setItem(cookieName, JSON.stringify(currentSampleFilter));
        this.updateOptions(currentSampleFilter);
        this.refresh();
      }
    });
  }

  updateOptions(options) {
    this.options.group = options.group;
    this.options.startkey = options.startEpoch
      ? Date.now() - options.startEpoch
      : undefined;
    this.options.endkey = undefined;
  }

  /**
   * Retrieve the allowed groups for the logged in user and create 'groupForm'
   * variable and 'groupFormSchema' (for onde module). It will keep in a cookie
   * the last selected group. Calling this method should reload automatically
   * @param {object} [options={}]
   * @param {string} [varName='groupForm'] contains the name of the variable containing the form value
   * @param {string} [schemaVarName='groupFormSchema'] contains the name of the variable containing the form schema
   * @param {string} [cookieName='eln-default-sample-group''] cookie name containing the last selected group
   * @param {string} [filter] filter applied on first refresh
   * @param {string} [autoRefresh=true] refresh least after initialization
   * @param {boolean} [listAllGroups=true] select from any group, even if not the a member
   * @return {string} the form to select group}
   */
  async initializeGroupForm(options = {}) {
    const {
      schemaVarName = 'groupFormSchema',
      varName = 'groupForm',
      cookieName = 'eln-default-sample-group',
      filter,
      autoRefresh = true,
      listAllGroups = false,
    } = options;

    let groups = [];
    if (listAllGroups) {
      groups = (await this.roc.getGroupsInfo()).map((g) => g.name);
    } else {
      groups = (await this.roc.getGroupMembership()).map((g) => g.name);
    }

    var possibleGroups = ['all', 'mine'].concat(groups);
    var defaultGroup = localStorage.getItem(cookieName);
    if (possibleGroups.indexOf(defaultGroup) === -1) {
      defaultGroup = 'all';
    }
    var schema = {
      type: 'object',
      properties: {
        group: {
          type: 'string',
          enum: possibleGroups,
          default: defaultGroup,
          required: true,
        },
      },
    };
    API.createData(schemaVarName, schema);

    let groupForm = await API.createData(varName, { group: defaultGroup });

    this.options.group = groupForm.group;
    if (autoRefresh) {
      await this.refresh(filter);
    }
    let mainData = Versioning.getData();
    mainData.onChange((evt) => {
      if (evt.jpath[0] === varName) {
        localStorage.setItem(cookieName, groupForm.group);
        this.options.group = String(groupForm.group);
        this.refresh();
      }
    });

    return groupForm;
  }
}

module.exports = Toc;
<commit_msg>fix: rename Toc range to Modified<commit_after>// this class is not really related to a sampleToc but can be used for any TOC

import API from 'src/util/api';
import Versioning from 'src/util/versioning';

let defaultOptions = {
  group: 'all',
  varName: 'sampleToc',
  viewName: 'sample_toc',
  filter: (entry) => !entry.value.hidden,
  sort: (a, b) => {
    if (a.value.modified && a.value.modified > b.value.modified) {
      return -1;
    } else if (
      a.value.modificationDate &&
      a.value.modificationDate > b.value.modificationDate
    ) {
      return -1;
    } else if (a.value.modified && a.value.modified < b.value.modified) {
      return 1;
    } else if (
      a.value.modificationDate &&
      a.value.modificationDate < b.value.modificationDate
    ) {
      return 1;
    } else {
      return 0;
    }
  },
};

class Toc {
  /**
   * Create an object managing the Toc
   * @param {object} [options={}]
   * @param {object} [roc=undefined]
   * @param {string} [options.group='mine'] Group to retrieve products. mine, all of a specific group name
   * @param {string} [options.varName='sampleToc']
   * @param {string} [options.viewName='sample_toc']
   * @param {function} [options.sort] Callback, by default sort by reverse date
   * @param {function} [options.filter] Callback to filter the result
   */
  constructor(roc, options = {}) {
    this.roc = roc;
    this.options = Object.assign({}, defaultOptions, options);
  }

  setFilter(filter) {
    this.options.filter = filter;
    return this.refresh();
  }

  /**
   * Retrieve the toc and put the result in the specified variable
   *
   */
  refresh(options = {}) {
    let {
      group,
      sort,
      filter,
      viewName,
      limit,
      startkey,
      endkey,
      key,
      descending,
    } = Object.assign({}, this.options, options);
    let mine = 0;
    let groups = '';
    group = String(group);
    if (group === 'mine') {
      mine = 1;
    } else if (group !== 'all') {
      groups = group;
    }
    return this.roc
      .query(viewName, {
        groups,
        mine,
        sort,
        filter,
        limit,
        startkey,
        endkey,
        key,
        descending,
        varName: this.options.varName,
      })
      .then((entries) => {
        if (this.options.callback) {
          entries.forEach(this.options.callback);
        }
        return entries;
      });
  }

  async initializeSampleFilter(options = {}) {
    const {
      twigVarName = 'sampleFilterTwig',
      varName = 'sampleFilter',
      cookieName = 'eln-default-sample-filter',
      filter,
      autoRefresh = true,
      listAllGroups = false,
    } = options;

    let groups = [];
    if (listAllGroups) {
      groups = (await this.roc.getGroupsInfo()).map((g) => g.name);
    } else {
      groups = (await this.roc.getGroupMembership()).map((g) => g.name);
    }

    const defaultSampleFilter = {
      group: 'mine',
      startEpoch: 24 * 3600 * 1000 * 31,
      endEpoch: '',
    };
    const sampleFilter = localStorage.getItem(cookieName)
      ? JSON.parse(localStorage.getItem(cookieName))
      : defaultSampleFilter;
    API.createData(varName, sampleFilter);

    this.updateOptions(sampleFilter);

    const sampleFilterTwig = `
Group: <select name="group">
<option value='all'>All</option>
<option value='mine'>Mine</option>
${groups.map((group) => '<option value="' + group + '">' + group + '</option>')}
</select>
Modified: <select name="startEpoch">
<option value='${24 * 3600 * 1000 * 31}'>Last month</option>
<option value='${24 * 3600 * 1000 * 91}'>Last 3 months</option>
<option value='${24 * 3600 * 1000 * 182}'>Last 6 months</option>
<option value='${24 * 3600 * 1000 * 365}'>Last year</option>
<option value='${24 * 3600 * 1000 * 730}'>Last 2 years</option>
<option value='${24 * 3600 * 1000 * 1830}'>Last 5 years</option>
<option value=''>Any time</option>
</select>
`;
    API.createData(twigVarName, sampleFilterTwig);

    if (autoRefresh) {
      await this.refresh(filter);
    }
    let mainData = Versioning.getData();
    mainData.onChange((evt) => {
      if (evt.jpath[0] === varName) {
        const currentSampleFilter = API.getData(varName).resurrect();
        localStorage.setItem(cookieName, JSON.stringify(currentSampleFilter));
        this.updateOptions(currentSampleFilter);
        this.refresh();
      }
    });
  }

  updateOptions(options) {
    this.options.group = options.group;
    this.options.startkey = options.startEpoch
      ? Date.now() - options.startEpoch
      : undefined;
    this.options.endkey = undefined;
  }

  /**
   * Retrieve the allowed groups for the logged in user and create 'groupForm'
   * variable and 'groupFormSchema' (for onde module). It will keep in a cookie
   * the last selected group. Calling this method should reload automatically
   * @param {object} [options={}]
   * @param {string} [varName='groupForm'] contains the name of the variable containing the form value
   * @param {string} [schemaVarName='groupFormSchema'] contains the name of the variable containing the form schema
   * @param {string} [cookieName='eln-default-sample-group''] cookie name containing the last selected group
   * @param {string} [filter] filter applied on first refresh
   * @param {string} [autoRefresh=true] refresh least after initialization
   * @param {boolean} [listAllGroups=true] select from any group, even if not the a member
   * @return {string} the form to select group}
   */
  async initializeGroupForm(options = {}) {
    const {
      schemaVarName = 'groupFormSchema',
      varName = 'groupForm',
      cookieName = 'eln-default-sample-group',
      filter,
      autoRefresh = true,
      listAllGroups = false,
    } = options;

    let groups = [];
    if (listAllGroups) {
      groups = (await this.roc.getGroupsInfo()).map((g) => g.name);
    } else {
      groups = (await this.roc.getGroupMembership()).map((g) => g.name);
    }

    var possibleGroups = ['all', 'mine'].concat(groups);
    var defaultGroup = localStorage.getItem(cookieName);
    if (possibleGroups.indexOf(defaultGroup) === -1) {
      defaultGroup = 'all';
    }
    var schema = {
      type: 'object',
      properties: {
        group: {
          type: 'string',
          enum: possibleGroups,
          default: defaultGroup,
          required: true,
        },
      },
    };
    API.createData(schemaVarName, schema);

    let groupForm = await API.createData(varName, { group: defaultGroup });

    this.options.group = groupForm.group;
    if (autoRefresh) {
      await this.refresh(filter);
    }
    let mainData = Versioning.getData();
    mainData.onChange((evt) => {
      if (evt.jpath[0] === varName) {
        localStorage.setItem(cookieName, groupForm.group);
        this.options.group = String(groupForm.group);
        this.refresh();
      }
    });

    return groupForm;
  }
}

module.exports = Toc;
<|endoftext|>


<commit_before>const mqtt = require('mqtt');

const client = mqtt.connect('mqtt://45.32.115.11');

export const idLampuFulfilment = (profile, data, response) => {
  let action = '';
  if (response.entities.on_off.value === 'on') {
    client.publish('lampu', 'on');
    action = 'dinyalakan';
  } else {
    client.publish('lampu', 'off');
    action = 'dimatikan';
  }
  const device = response.entities.iot_things.value;
  const place = response.entities.iot_place.value;
  const returnSpeech = `${profile.first_name}, ${device} ${place} sudah aku ${action}`;
  return returnSpeech;
};

export default idLampuFulfilment;
<commit_msg>Entities Bug Fix<commit_after>const mqtt = require('mqtt');

const client = mqtt.connect('mqtt://45.32.115.11');

export const idLampuFulfilment = (profile, data, response) => {
  let action = '';
  if (response.entities.on_off.value === 'on') {
    client.publish('lampu', 'on');
    action = 'dinyalakan';
  } else {
    client.publish('lampu', 'off');
    action = 'dimatikan';
  }
  const device = response.entities.iot_things[0].value;
  const place = response.entities.iot_place[0].value;
  const returnSpeech = `${profile.first_name}, ${device} ${place} sudah aku ${action}`;
  return returnSpeech;
};

export default idLampuFulfilment;
<|endoftext|>


<commit_before>
stage.loadFile( "rcsb://4w93.mmtf" ).then( function( o ){

    o.addRepresentation( "licorice", { sele: "[3L9]" } );

    // Get ring atoms for residue with name 3L9
    var ringAtomNames = [];
    o.structure.eachAtom( function( ap ) {
        if( ap.isRing() ){
            ringAtomNames.push( "." + ap.atomname );
        }
    }, new NGL.Selection( "[3L9]" ) );

    o.addRepresentation("spacefill", {
        sele: "[3L9] and ( " + ringAtomNames.join( " " ) + ")",
        scale: 0.25
    } );

    stage.autoView();

} );
<commit_msg>removed obsolete example<commit_after><|endoftext|>


<commit_before>var models = require('../models/index');

var ZiviService = {};

ZiviService.findBy = function (conditions, callback) {
  models.Zivi.find(conditions, callback);
};

ZiviService.findOneByName = function (name, callback) {
  ZiviService.findBy({name: name}, callback);
};

ZiviService.findAll = function (callback) {
  ZiviService.findBy({}, callback);
};

ZiviService.findAllBut = function (ziviExcluded, callback) {
  if (!ziviExcluded) {
    ZiviService.findAll(callback);
  } else {
    models.Zivi.find({
      _id: {
        $ne: ziviExcluded._id
      }
    }, callback);
  }
};

ZiviService.saveZivi = function (zivi, callback) {
  zivi.save(callback);
};

ZiviService.deleteZivi = function (zivi, callback) {
  models.DeletedZivi.create(zivi, function (err) {
    if (err) {
      callback && callback(err);
    } else {
      zivi.remove(callback);
    }
  })
};

ZiviService.createZivi = function (obj, callback) {
  models.Zivi.create(obj, callback);
};

ZiviService.updateZiviByName = function (name, spec, callback) {
  ZiviService.findOneByName(name, function (err, zivi) {
    if (err) {
      return callback && callback(err);
    }
    for (var propName in obj) {
      if (obj.hasOwnProperty(propName) && propName !== '_id') {
        zivi[propName] = obj[propName];
      }
    }
    ZiviService.saveZivi(zivi, callback);
  })
};

module.exports = ZiviService;
<commit_msg>Handle non-existing Zivis in zivi.service updateZiviByName<commit_after>var models = require('../models/index');

var ZiviService = {};

ZiviService.findBy = function (conditions, callback) {
  models.Zivi.find(conditions, callback);
};

ZiviService.findOneByName = function (name, callback) {
  ZiviService.findBy({name: name}, callback);
};

ZiviService.findAll = function (callback) {
  ZiviService.findBy({}, callback);
};

ZiviService.findAllBut = function (ziviExcluded, callback) {
  if (!ziviExcluded) {
    ZiviService.findAll(callback);
  } else {
    models.Zivi.find({
      _id: {
        $ne: ziviExcluded._id
      }
    }, callback);
  }
};

ZiviService.saveZivi = function (zivi, callback) {
  zivi.save(callback);
};

ZiviService.deleteZivi = function (zivi, callback) {
  models.DeletedZivi.create(zivi, function (err) {
    if (err) {
      callback && callback(err);
    } else {
      zivi.remove(callback);
    }
  })
};

ZiviService.createZivi = function (obj, callback) {
  models.Zivi.create(obj, callback);
};

ZiviService.updateZiviByName = function (name, spec, callback) {
  ZiviService.findOneByName(name, function (err, zivi) {
    if (err) {
      return callback && callback(err);
    } else if (!zivi) {
      return callback && callback({code: 'ENOTFOUND', message: 'No zivi by that name: ' + name});
    }
    for (var propName in obj) {
      if (obj.hasOwnProperty(propName) && propName !== '_id') {
        zivi[propName] = obj[propName];
      }
    }
    ZiviService.saveZivi(zivi, callback);
  })
};

module.exports = ZiviService;
<|endoftext|>