<commit_before>// include gulp, package and modules
const gulp = require('gulp');
const pkg = require('./package.json');
const $ = require('gulp-load-plugins')();

// banners for output files
const banners = {
	max: [
		'/**',
		` * Grindstone JavaScript Library v${pkg.version}`,
		` * ${pkg.repository.url}`,
		' * ',
		` * Copyright (c) 2014, ${new Date().getFullYear()} ${pkg.author.name} and contributors`,
		' * Released under the MIT license',
		` * ${pkg.repository.url}/blob/master/LICENSE`,
		' */',
		'\n'
	].join('\n'),
	min: [
		`/* Grindstone JavaScript Library v${pkg.version} |`,
		`Copyright (c) 2014, ${new Date().getFullYear()} ${pkg.author.name} and contributors |`,
		`${pkg.repository.url}/blob/master/LICENSE */\n`
	].join(' ')
};

// clean output directory
gulp.task('clean', () => {
	return gulp.src('dist', { read: false })
		.pipe($.clean({ force: true }));
});

// concatenate all the things
gulp.task('concat', ['clean'], () => {
	return gulp.src(['src/templates/Intro.js', 'src/Core.js', 'src/modules/*.js', 'src/templates/Outro.js'])
		.pipe($.concat(`${pkg.name}-v${pkg.version}.js`))
		.pipe($.header(banners.max))
		.pipe(gulp.dest('dist'));
});

// uglify it
gulp.task('uglify', ['concat'], () => {
	return gulp.src(`dist/${pkg.name}-v${pkg.version}.js`)
		.pipe($.uglify())
		.pipe($.header(banners.min))
		.pipe($.rename(`${pkg.name}-v${pkg.version}.min.js`))
		.pipe(gulp.dest('dist'));
});

// watch for changes
gulp.task('watch', () => {
	gulp.watch('src/**/*.js', () => {
		gulp.run('build');
	});
});

// build
gulp.task('build', ['clean', 'concat', 'uglify']);<commit_msg>Gettin' anal about consistency<commit_after>// include gulp, package and modules
const gulp = require('gulp');
const pkg = require('./package.json');
const $ = require('gulp-load-plugins')();

// banners for output files
const banners = {
	max: [
		`/**`,
		` * Grindstone JavaScript Library v${pkg.version}`,
		` * ${pkg.repository.url}`,
		` * `,
		` * Copyright (c) 2014, ${new Date().getFullYear()} ${pkg.author.name} and contributors`,
		` * Released under the MIT license`,
		` * ${pkg.repository.url}/blob/master/LICENSE`,
		` */`,
		`\n`
	].join('\n'),
	min: [
		`/* Grindstone JavaScript Library v${pkg.version} |`,
		`Copyright (c) 2014, ${new Date().getFullYear()} ${pkg.author.name} and contributors |`,
		`${pkg.repository.url}/blob/master/LICENSE */\n`
	].join(' ')
};

// clean output directory
gulp.task('clean', () => {
	return gulp.src('dist', { read: false })
		.pipe($.clean({ force: true }));
});

// concatenate all the things
gulp.task('concat', ['clean'], () => {
	return gulp.src(['src/templates/Intro.js', 'src/Core.js', 'src/modules/*.js', 'src/templates/Outro.js'])
		.pipe($.concat(`${pkg.name}-v${pkg.version}.js`))
		.pipe($.header(banners.max))
		.pipe(gulp.dest('dist'));
});

// uglify it
gulp.task('uglify', ['concat'], () => {
	return gulp.src(`dist/${pkg.name}-v${pkg.version}.js`)
		.pipe($.uglify())
		.pipe($.header(banners.min))
		.pipe($.rename(`${pkg.name}-v${pkg.version}.min.js`))
		.pipe(gulp.dest('dist'));
});

// watch for changes
gulp.task('watch', () => {
	gulp.watch('src/**/*.js', () => {
		gulp.run('build');
	});
});

// build
gulp.task('build', ['clean', 'concat', 'uglify']);<|endoftext|>


<commit_before>import './module/radio-tab';
import gui from './module/gui';
import controller from './module/controller-webform-fieldsubmission';
import settings from './module/settings';
import connection from './module/connection';
import { init as initTranslator, t, localize } from './module/translator';
import calculationModule from 'enketo-core/src/js/calculate';
import preloadModule from 'enketo-core/src/js/preload';
import oc from './module/custom';

const loader = document.querySelector( '.main-loader' );
const formheader = document.querySelector( '.main > .paper > .form-header' );
const footer = document.querySelector( '.form-footer' );
const survey = {
    enketoId: settings.enketoId,
    serverUrl: settings.serverUrl,
    xformId: settings.xformId,
    xformUrl: settings.xformUrl,
    instanceId: settings.instanceId
};
const range = document.createRange();

initTranslator( survey )
    .then( connection.getFormParts )
    .then( formParts => {
        if ( location.pathname.indexOf( '/edit/' ) > -1 || location.pathname.indexOf( '/view/' ) > -1 ) {
            if ( survey.instanceId ) {
                return connection.getExistingInstance( survey )
                    .then( response => {
                        formParts.instance = response.instance;
                        formParts.instanceAttachments = response.instanceAttachments;

                        // TODO: this will fail massively if instanceID is not populated (will use POST instead of PUT). Maybe do a check?
                        return formParts;
                    } );
            } else if ( location.pathname.indexOf( '/edit/' ) > -1 ) {
                throw new Error( 'This URL is invalid' );
            }
        }

        return formParts;
    } )
    .then( formParts => {
        if ( formParts.form && formParts.model ) {
            return gui.swapTheme( formParts );
        } else {
            throw new Error( t( 'error.unknown' ) );
        }
    } )
    .then( formParts => {
        if ( /\/fs\/dnc?\//.test( window.location.pathname ) ) {
            return _readonlify( formParts, true );
        } else if ( settings.type === 'view' ) {
            return _readonlify( formParts, false );
        }

        return formParts;
    } )
    .then( connection.getMaximumSubmissionSize )
    .then( _updateMaxSizeSetting )
    .then( _init )
    .catch( _showErrorOrAuthenticate );

function _updateMaxSizeSetting( survey ) {
    if ( survey.maxSize ) {
        // overwrite default max size
        settings.maxSize = survey.maxSize;
    }

    return survey;
}

function _showErrorOrAuthenticate( error ) {
    loader.classList.add( 'fail' );
    if ( error.status === 401 ) {
        window.location.href = `/login?return_url=${encodeURIComponent( window.location.href )}`;
    } else {
        gui.alert( error.message, t( 'alert.loaderror.heading' ) );
    }
}

/**
 * Converts questions to readonly
 * Disables calculations, deprecatedID mechanism and preload items.
 *
 * @param {object} formParts - formParts object
 * @param {boolean} notesEnabled - whether notes are enabled
 * @return {object}          formParts object
 */
function _readonlify( formParts, notesEnabled ) {
    // Styling changes
    document.querySelector( 'body' ).classList.add( 'oc-view' );

    // Partially disable calculations in Enketo Core
    console.info( 'Calculations restricted to clinicaldata only.' );
    calculationModule.originalUpdate = calculationModule.update;
    calculationModule.update = function( updated ) {
        return calculationModule.originalUpdate.call( this, updated, '[data-oc-external="clinicaldata"]' );
    };
    console.info( 'Setvalue disabled.' );
    calculationModule.setvalue = () => {};

    // Completely disable preload items
    console.info( 'Preloaders disabled.' );
    preloadModule.init = () => {};
    // change status message
    const msg = notesEnabled ? t( 'fieldsubmission.noteonly.msg' ) : t( 'fieldsubmission.readonly.msg' );
    formheader.prepend( range.createContextualFragment( `<div class="fieldsubmission-status readonly">${msg}</div>` ) );
    footer.prepend( range.createContextualFragment( `<div class="form-footer__feedback fieldsubmission-status readonly">${msg}</div>` ) );

    formParts.formFragment = range.createContextualFragment( formParts.form );

    // Note: Enketo made a syntax error by adding the readonly attribute on a <select>
    // Hence, we cannot use .prop('readonly', true). We'll continue the syntax error.
    [ ...formParts.formFragment.querySelectorAll( 'input:not([readonly]), textarea:not([readonly]), select:not(#form-languages):not([readonly])' ) ]
        .filter( el =>  notesEnabled ? !el.closest( '.or-appearance-dn' ) : true )
        .forEach( el => {
            el.setAttribute( 'readonly', 'readonly' );
            el.classList.add( 'readonly-forced' );
        } );

    // Properly make native selects readonly (for touchscreens)
    formParts.formFragment.querySelectorAll( 'select:not(#form-languages) option' )
        .forEach( el => el.disabled = true );
    // Prevent adding an Add/Remove UI on repeats
    formParts.formFragment.querySelectorAll( '.or-repeat-info' )
        .forEach( el => el.setAttribute( 'data-repeat-fixed', 'fixed' ) );
    // Record load warning but keep loading
    if ( settings.loadWarning ) {
        if( !formParts.loadErrors ){
            formParts.loadErrors = [];
        }
        formParts.loadErrors.push( settings.loadWarning );
    }

    return formParts;
}

function _init( formParts ) {
    let error;

    return new Promise( ( resolve, reject ) => {
        if ( formParts && formParts.form && formParts.model ) {
            const formFragment = formParts.formFragment || range.createContextualFragment( formParts.form );
            formheader.after( formFragment );
            const formEl = document.querySelector( 'form.or' );

            controller.init( formEl, {
                modelStr: formParts.model,
                instanceStr: formParts.instance,
                external: formParts.externalData,
                instanceAttachments: formParts.instanceAttachments
            }, formParts.loadErrors ).then( form => {
                //formParts.languages = form.languages; // be careful form is undefined if there were load errors
                formParts.htmlView = formEl;
                const titleEl = document.querySelector( '#form-title' );
                const titleText = settings.pid ? `${settings.pid}: ${titleEl.textContent}` : titleEl.textContent;
                document.querySelector( 'head>title' ).textContent = titleText;
                titleEl.textContent = titleText;
                if ( formParts.instance ) {
                    oc.addSignedStatus( form );
                }
                if ( settings.print ) {
                    gui.applyPrintStyle();
                }
                localize( formEl );
                resolve( formParts );
            } );
        } else if ( formParts ) {
            error = new Error( 'Form not complete.' );
            error.status = 400;
            reject( error );
        } else {
            error = new Error( 'Form not found' );
            error.status = 404;
            reject( error );
        }
    } );
}
<commit_msg>fixed: OC readonly/note-only views load with a TypeError,<commit_after>import './module/radio-tab';
import gui from './module/gui';
import controller from './module/controller-webform-fieldsubmission';
import settings from './module/settings';
import connection from './module/connection';
import { init as initTranslator, t, localize } from './module/translator';
import calculationModule from 'enketo-core/src/js/calculate';
import preloadModule from 'enketo-core/src/js/preload';
import oc from './module/custom';

const loader = document.querySelector( '.main-loader' );
const formheader = document.querySelector( '.main > .paper > .form-header' );
const footer = document.querySelector( '.form-footer' );
const survey = {
    enketoId: settings.enketoId,
    serverUrl: settings.serverUrl,
    xformId: settings.xformId,
    xformUrl: settings.xformUrl,
    instanceId: settings.instanceId
};
const range = document.createRange();

initTranslator( survey )
    .then( connection.getFormParts )
    .then( formParts => {
        if ( location.pathname.indexOf( '/edit/' ) > -1 || location.pathname.indexOf( '/view/' ) > -1 ) {
            if ( survey.instanceId ) {
                return connection.getExistingInstance( survey )
                    .then( response => {
                        formParts.instance = response.instance;
                        formParts.instanceAttachments = response.instanceAttachments;

                        // TODO: this will fail massively if instanceID is not populated (will use POST instead of PUT). Maybe do a check?
                        return formParts;
                    } );
            } else if ( location.pathname.indexOf( '/edit/' ) > -1 ) {
                throw new Error( 'This URL is invalid' );
            }
        }

        return formParts;
    } )
    .then( formParts => {
        if ( formParts.form && formParts.model ) {
            return gui.swapTheme( formParts );
        } else {
            throw new Error( t( 'error.unknown' ) );
        }
    } )
    .then( formParts => {
        if ( /\/fs\/dnc?\//.test( window.location.pathname ) ) {
            return _readonlify( formParts, true );
        } else if ( settings.type === 'view' ) {
            return _readonlify( formParts, false );
        }

        return formParts;
    } )
    .then( connection.getMaximumSubmissionSize )
    .then( _updateMaxSizeSetting )
    .then( _init )
    .catch( _showErrorOrAuthenticate );

function _updateMaxSizeSetting( survey ) {
    if ( survey.maxSize ) {
        // overwrite default max size
        settings.maxSize = survey.maxSize;
    }

    return survey;
}

function _showErrorOrAuthenticate( error ) {
    loader.classList.add( 'fail' );
    if ( error.status === 401 ) {
        window.location.href = `/login?return_url=${encodeURIComponent( window.location.href )}`;
    } else {
        gui.alert( error.message, t( 'alert.loaderror.heading' ) );
    }
}

/**
 * Converts questions to readonly
 * Disables calculations, deprecatedID mechanism and preload items.
 *
 * @param {object} formParts - formParts object
 * @param {boolean} notesEnabled - whether notes are enabled
 * @return {object}          formParts object
 */
function _readonlify( formParts, notesEnabled ) {
    // Styling changes
    document.querySelector( 'body' ).classList.add( 'oc-view' );

    // Partially disable calculations in Enketo Core
    console.info( 'Calculations restricted to clinicaldata only.' );
    calculationModule.originalUpdate = calculationModule.update;
    calculationModule.update = function( updated ) {
        return calculationModule.originalUpdate.call( this, updated, '[data-oc-external="clinicaldata"]' );
    };
    console.info( 'Setvalue disabled.' );
    calculationModule.setvalue = () => {};

    // Completely disable preload items
    console.info( 'Preloaders disabled.' );
    preloadModule.init = () => {};
    // change status message
    const msg = notesEnabled ? t( 'fieldsubmission.noteonly.msg' ) : t( 'fieldsubmission.readonly.msg' );
    formheader.prepend( range.createContextualFragment( `<div class="fieldsubmission-status readonly">${msg}</div>` ) );
    footer.prepend( range.createContextualFragment( `<div class="form-footer__feedback fieldsubmission-status readonly">${msg}</div>` ) );

    formParts.formFragment = range.createContextualFragment( formParts.form );

    // Note: Enketo made a syntax error by adding the readonly attribute on a <select>
    // Hence, we cannot use .prop('readonly', true). We'll continue the syntax error.
    [ ...formParts.formFragment.querySelectorAll( 'input:not([readonly]), textarea:not([readonly]), select:not(#form-languages):not([readonly])' ) ]
        .filter( el => !el.closest( '#or-calculated-items, #or-preload-items, #or-setvalue-items' ) )
        .filter( el =>  notesEnabled ? !el.closest( '.or-appearance-dn' ) : true )
        .forEach( el => {
            el.setAttribute( 'readonly', 'readonly' );
            el.classList.add( 'readonly-forced' );
        } );

    // Properly make native selects readonly (for touchscreens)
    formParts.formFragment.querySelectorAll( 'select:not(#form-languages) option' )
        .forEach( el => el.disabled = true );
    // Prevent adding an Add/Remove UI on repeats
    formParts.formFragment.querySelectorAll( '.or-repeat-info' )
        .forEach( el => el.setAttribute( 'data-repeat-fixed', 'fixed' ) );
    // Record load warning but keep loading
    if ( settings.loadWarning ) {
        if( !formParts.loadErrors ){
            formParts.loadErrors = [];
        }
        formParts.loadErrors.push( settings.loadWarning );
    }

    return formParts;
}

function _init( formParts ) {
    let error;

    return new Promise( ( resolve, reject ) => {
        if ( formParts && formParts.form && formParts.model ) {
            const formFragment = formParts.formFragment || range.createContextualFragment( formParts.form );
            formheader.after( formFragment );
            const formEl = document.querySelector( 'form.or' );

            controller.init( formEl, {
                modelStr: formParts.model,
                instanceStr: formParts.instance,
                external: formParts.externalData,
                instanceAttachments: formParts.instanceAttachments
            }, formParts.loadErrors ).then( form => {
                //formParts.languages = form.languages; // be careful form is undefined if there were load errors
                formParts.htmlView = formEl;
                const titleEl = document.querySelector( '#form-title' );
                const titleText = settings.pid ? `${settings.pid}: ${titleEl.textContent}` : titleEl.textContent;
                document.querySelector( 'head>title' ).textContent = titleText;
                titleEl.textContent = titleText;
                if ( formParts.instance ) {
                    oc.addSignedStatus( form );
                }
                if ( settings.print ) {
                    gui.applyPrintStyle();
                }
                localize( formEl );
                resolve( formParts );
            } );
        } else if ( formParts ) {
            error = new Error( 'Form not complete.' );
            error.status = 400;
            reject( error );
        } else {
            error = new Error( 'Form not found' );
            error.status = 404;
            reject( error );
        }
    } );
}
<|endoftext|>


<commit_before>exports.init = function () {
    return [
        "CREATE TABLE sources    (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT);",
        "CREATE TABLE datapoints (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,name TEXT,type INTEGER);",
        "CREATE TABLE ts_number  (id INTEGER, ts INTEGER, val REAL,    ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
        "CREATE TABLE ts_string  (id INTEGER, ts INTEGER, val TEXT,    ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
        "CREATE TABLE ts_bool    (id INTEGER, ts INTEGER, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
    ];
};

exports.destroy = function () {
    return [
        "DROP TABLE ts_number;",
        "DROP TABLE ts_string;",
        "DROP TABLE ts_bool;",
        "DROP TABLE sources;",
        "DROP TABLE datapoints;"
    ];
};
exports.insert = function (index, state, from, db) {
    if (db === "ts_bool")   state.val = state.val ? 1 : 0;
    if (db === "ts_string") state.val = "'" + state.val + "'";
    return "INSERT INTO " + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + state.q + ");";
};

exports.retention = function (index, db, retention) {
    var d = new Date();
    d.setSeconds(-retention);
    var query = "DELETE FROM " + db + " WHERE";
    query += " id=" + index;
    query += " AND ts < " + Math.round(d.getTime() / 1000);
    query += ";";
    return query;
};

exports.getIdSelect = function (name) {
    return "SELECT id, type FROM datapoints WHERE name='" + name + "';";
};

exports.getIdInsert = function (name, type) {
    return  "INSERT INTO datapoints (name, type) VALUES('" + name + "', " + type + ");";
};

exports.getFromSelect = function (from) {
    return "SELECT id FROM sources WHERE name='" + from + "';";
};

exports.getFromInsert = function (from) {
    return "INSERT INTO sources (name) VALUES('" + from + "');";
};

exports.getHistory = function (db, options) {
    var query = "SELECT ts, val" +
        (!options.id  ? (", " + db + ".id as id") : "") +
        (options.ack  ? ", ack" : "") +
        (options.from ? (", sources.name as 'from'") : "") +
        (options.q    ? ", q" : "") + " FROM " + db;

    if (options.from) {
        query += " INNER JOIN sources ON sources.id=" + db + "._from";
    }

    var where = "";

    if (options.id) {
        where += " " + db + ".id=" + options.id;
    }
    if (options.end) {
        where += (where ? " AND" : "") + " " + db + ".ts < " + options.end;
    }
    if (options.start) {
        where += (where ? " AND" : "") + " " + db + ".ts >= " + options.start;
    }

    if (where) query += " WHERE " + where;

    query += " ORDER BY " + db + ".ts";

    if (!options.start && options.count) {
        query += " DESC LIMIT " + options.count;
    } else {
        query += " ASC";
    }

    query += ";";
    return query;
};<commit_msg>Update sqlite.js<commit_after>exports.init = function () {
    return [
        "CREATE TABLE sources    (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT);",
        "CREATE TABLE datapoints (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,name TEXT,type INTEGER);",
        "CREATE TABLE ts_number  (id INTEGER, ts INTEGER, val REAL,    ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
        "CREATE TABLE ts_string  (id INTEGER, ts INTEGER, val TEXT,    ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
        "CREATE TABLE ts_bool    (id INTEGER, ts INTEGER, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
    ];
};

exports.destroy = function () {
    return [
        "DROP TABLE ts_number;",
        "DROP TABLE ts_string;",
        "DROP TABLE ts_bool;",
        "DROP TABLE sources;",
        "DROP TABLE datapoints;"
    ];
};
exports.insert = function (index, state, from, db) {
    if (db === "ts_bool")   state.val = state.val ? 1 : 0;
    if (db === "ts_string") state.val = "'" + state.val + "'";
    return "INSERT INTO " + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + state.q + ");";
};

exports.retention = function (index, db, retention) {
    var d = new Date();
    d.setSeconds(-retention);
    var query = "DELETE FROM " + db + " WHERE";
    query += " id=" + index;
    query += " AND ts < " + Math.round(d.getTime() / 1000);
    query += ";";
    return query;
};

exports.getIdSelect = function (name) {
    return "SELECT id, type FROM datapoints WHERE name='" + name + "';";
};

exports.getIdInsert = function (name, type) {
    return  "INSERT INTO datapoints (name, type) VALUES('" + name + "', " + type + ");";
};

exports.getFromSelect = function (from) {
    return "SELECT id FROM sources WHERE name='" + from + "';";
};

exports.getFromInsert = function (from) {
    return "INSERT INTO sources (name) VALUES('" + from + "');";
};

exports.getHistory = function (db, options) {
    var query = "SELECT ts, val" +
        (!options.id  ? (", " + db + ".id as id") : "") +
        (options.ack  ? ", ack" : "") +
        (options.from ? (", sources.name as 'from'") : "") +
        (options.q    ? ", q" : "") + " FROM " + db;

    if (options.from) {
        query += " INNER JOIN sources ON sources.id=" + db + "._from";
    }

    var where = "";

    if (options.id) {
        where += " " + db + ".id=" + options.id;
    }
    if (options.end) {
        where += (where ? " AND" : "") + " " + db + ".ts < " + options.end;
    }
    if (options.start) {
        where += (where ? " AND" : "") + " " + db + ".ts >= " + options.start;

        //add last value before start with timestamp set to start
        var subQuery, subWhere;
        subQuery = " SELECT '" + options.start + "' as ts, val" +
            (!options.id  ? (", " + db + ".id as id") : "") +
            (options.ack  ? ", ack" : "") +
            (options.from ? (", sources.name as 'from'") : "") +
            (options.q    ? ", q" : "") + " FROM " + db;
        if (options.from) {
            subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
        }
        subWhere = "";
        if (options.id) {
            subWhere += " " + db + ".id=" + options.id;
        }
        subWhere += (subWhere ? " AND" : "") + " " + db + ".ts <= " + options.start;
        if (subWhere) subQuery += " WHERE " + subWhere;
        subQuery += " ORDER BY " + db + ".ts DESC LIMIT 1";
        where += " UNION (" + subQuery + ")";
    }

    if (where) query += " WHERE " + where;

    query += " ORDER BY ts";

    if (!options.start && options.count) {
        query += " DESC LIMIT " + options.count;
    } else {
        query += " ASC";
    }

    query += ";";
    return query;
};
<|endoftext|>


<commit_before>const dev = process.env.NODE_ENV !== 'production'
// const goal = process.env.NODE_ENV

const next = require('next')
const express = require('express')
const LRUCache = require('lru-cache')
const helmet = require('helmet')
const mobxReact = require('mobx-react')
const R = require('ramda')

const app = next({ dev, quiet: false })
const handle = app.getRequestHandler()
const SERVE_PORT = process.env.SERVE_PORT || 3000

// This is where we cache our rendered HTML pages
const ssrCache = new LRUCache({
  max: 1000, // cache item count
  // maxAge: 1000 * 60 * 60, // 1hour
  maxAge: 1000 * 30, // 30 ses
})

mobxReact.useStaticRendering(true)

const HOME_PAGE = '/home/posts'
app.prepare().then(() => {
  const server = express()
  server.use(express.static('static'))
  server.use(helmet())

  server.use((req, res, next) => {
    const str = 'www.'
    const newUrl = `${req.protocol}://${req.hostname.slice(str.length)}:80${
      req.originalUrl
    }`

    if (req.hostname.indexOf(str) === 0) {
      res.redirect(301, newUrl)
    } else {
      next()
    }
  })

  server.get('/_next/:page?', (req, res) => handle(req, res))

  server.get('/', (req, res) => {
    return res.redirect(HOME_PAGE)
  })

  server.get('/user/:userId', (req, res) => {
    // return app.render(req, res, '/user', req.query)
    return renderAndCache(req, res, '/user', req.query)
  })

  server.get('/:community/post/:id', (req, res) => {
    /* return app.render(req, res, '/post', req.query) */
    return renderAndCache(req, res, '/post', req.query)
  })

  server.get('/:community/job/:id', (req, res) => {
    /* return app.render(req, res, '/job', req.query) */
    return renderAndCache(req, res, '/job', req.query)
  })

  server.get('/:community/video/:id', (req, res) => {
    /* return app.render(req, res, '/video', req.query) */
    return renderAndCache(req, res, '/video', req.query)
  })

  server.get('/:community/repo/:id', (req, res) => {
    /* return app.render(req, res, '/repo', req.query) */
    return renderAndCache(req, res, '/repo', req.query)
  })

  server.get('/communities', (req, res) => {
    /* return app.render(req, res, '/communities', req.query) */
    return res.redirect('/communities/pl')
    // return renderAndCache(req, res, '/communities/pl', req.query)
  })

  server.get('/communities/:category', (req, res) => {
    /* return app.render(req, res, '/communities', req.query) */
    return renderAndCache(req, res, '/communities', req.query)
  })

  server.get('/:community/:thread', (req, res) => {
    if (
      R.has('preview', req.query) &&
      R.has('id', req.query) &&
      R.has('community', req.query)
    ) {
      const { community, preview, id } = req.query
      return res.redirect(`/${community}/${preview}/${id}`)
    }
    console.log('=== community page')
    /* return app.render(req, res, '/community', req.query) */
    return renderAndCache(req, res, '/community', req.query)
  })

  server.get('*', (req, res) => handle(req, res))

  server.listen(SERVE_PORT, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${SERVE_PORT}`)
  })
})

/*
 * NB: make sure to modify this to take into account anything that should trigger
 * an immediate page change (e.g a locale stored in req.session)
 */
function getCacheKey(req) {
  return `${req.url}`
}

async function renderAndCache(req, res, pagePath, queryParams) {
  const key = getCacheKey(req)

  // If we have a page in the cache, let's serve it
  if (ssrCache.has(key)) {
    res.setHeader('x-cache', 'HIT')
    res.send(ssrCache.get(key))
    return
  }

  try {
    // If not let's render the page into HTML
    const html = await app.renderToHTML(req, res, pagePath, queryParams)

    // Something is wrong with the request, let's skip the cache
    if (res.statusCode !== 200) {
      res.send(html)
      return
    }

    // Let's cache this page
    ssrCache.set(key, html)

    res.setHeader('x-cache', 'MISS')
    res.send(html)
  } catch (err) {
    app.renderError(err, req, res, pagePath, queryParams)
  }
}
<commit_msg>refactor(server): fmt code, add comments<commit_after>const dev = process.env.NODE_ENV !== 'production'
// const goal = process.env.NODE_ENV

const next = require('next')
const express = require('express')
const LRUCache = require('lru-cache')
const helmet = require('helmet')
const mobxReact = require('mobx-react')
const R = require('ramda')

const app = next({ dev, quiet: false })
const handle = app.getRequestHandler()
const SERVE_PORT = process.env.SERVE_PORT || 3000

// SSR for mobx
mobxReact.useStaticRendering(true)

// This is where we cache our rendered HTML pages
const ssrCache = new LRUCache({
  max: 1000, // cache item count
  // maxAge: 1000 * 60 * 60, // 1hour
  maxAge: 1000 * 30, // 30 ses
})

// redirect all the www request to non-www version
const reDirectToNakedUrl = (req, res, next) => {
  const w3 = 'www.'
  const { protocol: ptl, hostname: host, originalUrl } = req

  if (host.indexOf(w3) === 0) {
    const nakedUrl = `${ptl}://${host.slice(w3.length)}:80${originalUrl}`
    return res.redirect(301, nakedUrl)
  }

  next()
}

const HOME_PAGE = '/home/posts'
app.prepare().then(() => {
  const server = express()
  server.use(reDirectToNakedUrl)
  server.use(express.static('static'))
  server.use(helmet())

  server.get('/_next/:page?', (req, res) => handle(req, res))

  server.get('/', (req, res) => {
    return res.redirect(HOME_PAGE)
  })

  server.get('/user/:userId', (req, res) => {
    // return app.render(req, res, '/user', req.query)
    return renderAndCache(req, res, '/user', req.query)
  })

  server.get('/:community/post/:id', (req, res) => {
    /* return app.render(req, res, '/post', req.query) */
    return renderAndCache(req, res, '/post', req.query)
  })

  server.get('/:community/job/:id', (req, res) => {
    /* return app.render(req, res, '/job', req.query) */
    return renderAndCache(req, res, '/job', req.query)
  })

  server.get('/:community/video/:id', (req, res) => {
    /* return app.render(req, res, '/video', req.query) */
    return renderAndCache(req, res, '/video', req.query)
  })

  server.get('/:community/repo/:id', (req, res) => {
    /* return app.render(req, res, '/repo', req.query) */
    return renderAndCache(req, res, '/repo', req.query)
  })

  server.get('/communities', (req, res) => {
    /* return app.render(req, res, '/communities', req.query) */
    return res.redirect('/communities/pl')
    // return renderAndCache(req, res, '/communities/pl', req.query)
  })

  server.get('/communities/:category', (req, res) => {
    /* return app.render(req, res, '/communities', req.query) */
    return renderAndCache(req, res, '/communities', req.query)
  })

  server.get('/:community/:thread', (req, res) => {
    if (
      R.has('preview', req.query) &&
      R.has('id', req.query) &&
      R.has('community', req.query)
    ) {
      const { community, preview, id } = req.query
      return res.redirect(`/${community}/${preview}/${id}`)
    }
    console.log('=== community page')
    /* return app.render(req, res, '/community', req.query) */
    return renderAndCache(req, res, '/community', req.query)
  })

  server.get('*', (req, res) => handle(req, res))

  server.listen(SERVE_PORT, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${SERVE_PORT}`)
  })
})

/*
 * NB: make sure to modify this to take into account anything that should trigger
 * an immediate page change (e.g a locale stored in req.session)
 */
function getCacheKey(req) {
  return `${req.url}`
}

async function renderAndCache(req, res, pagePath, queryParams) {
  const key = getCacheKey(req)

  // If we have a page in the cache, let's serve it
  if (ssrCache.has(key)) {
    res.setHeader('x-cache', 'HIT')
    res.send(ssrCache.get(key))
    return
  }

  try {
    // If not let's render the page into HTML
    const html = await app.renderToHTML(req, res, pagePath, queryParams)

    // Something is wrong with the request, let's skip the cache
    if (res.statusCode !== 200) {
      res.send(html)
      return
    }

    // Let's cache this page
    ssrCache.set(key, html)

    res.setHeader('x-cache', 'MISS')
    res.send(html)
  } catch (err) {
    app.renderError(err, req, res, pagePath, queryParams)
  }
}
<|endoftext|>


<commit_before>// Dependencies
// ============

var gulp = require('gulp'),

    // Styles
    sass = require('gulp-sass'),
    autoprefix = require('gulp-autoprefixer'),
    minify = require('gulp-minify-css'),

    // Scripts
    uglify = require('gulp-uglify'),
    strip = require('gulp-strip-debug'),
    concat = require('gulp-concat'),

    // Images
    img = require('gulp-imagemin'),
    cache = require('gulp-cache'),

    // Other
    util = require('gulp-util'),
    del = require('del'),
    notify = require('gulp-notify'),
    notifier = require('node-notifier'),
    merge = require('merge-stream');

// Assets
// ======

var paths = {
    assets: {
        styles: {
            dir: 'assets/styles',
            files: 'assets/styles/**/*.scss',
        },
        js: {
            dir: 'assets/scripts/',
            files: [
                'assets/scripts/vendor/**/*.js',
                'assets/scripts/src/**/*.js',
                'assets/scripts/main.js'
            ],
        },
        img: {
            dir: 'assets/images',
            files: 'assets/images/**/*'
        }
    },
    public: {
        styles: 'public/styles',
        js: 'public/scripts',
        img: 'public/images',
    }
}

// General Settings
// ================

var settings = {
    autoprefix: {
        versions: 'last 4 version'
    }
}

// Deployment
// ==========

var deployment = {

    // The files we want to deploy
    files: [
        '**/*',
        '!{_deploy,_deploy/**}',
        '!{assets,assets/**}',
        '!{node_modules,node_modules/**}',
        '!package.json',
        '!gulpfile.js',
        '!readme.md'
    ],

    // The folder to store them in
    destination: '_deploy'
}

// Styles
// ======
// Grabs everything inside the styles & sprites
// directories, concantinates and compiles scss,
// builds sprites, and then outputs them to their
// respective target directories.

gulp.task('styles', function() {
    gulp.src(paths.assets.styles.files)
        .pipe(sass())
        .pipe(autoprefix(settings.autoprefix.versions))
        .pipe(gulp.dest(paths.public.styles));
});

// Scripts
// =======
// Grabs everything inside the js directory,
// concantinates and minifies, and then outputs
// them to the target directory.

gulp.task('scripts', function() {
    gulp.src(paths.assets.js.files)
        .pipe(concat('main.js'))
        .pipe(gulp.dest(paths.public.js));
});

// Images
// ======
// Grabs everything inside the img directory,
// optimises each image, and then outputs them to
// the target directory.

gulp.task('images', function() {
    gulp.src(paths.assets.img.files)
        .pipe(gulp.dest(paths.public.img));
});

// Cache-buster
// ============
// Completely clear the cache to stop image-min
// outputting oncorrect image names etc.

gulp.task('clear', function(done) {
    return cache.clearAll(done);
});

// Cleaner
// =======
// Deletes all the public asset folders.

gulp.task('clean', function() {
    return del([
        paths.public.styles,
        paths.public.js,
        paths.public.img
    ]);
});

// Watcher
// =======
// Watches the different directores for changes and then
// runs their relevant tasks and livereloads.

gulp.task('watch', function() {
    // Run the appropriate task when assets change
    gulp.watch(paths.assets.styles.files, ['styles']);
    gulp.watch(paths.assets.js.files, ['scripts']);
    gulp.watch(paths.assets.img.files, ['images']);
});

// Production assets
// =================
// Goes through all our assets and readies them for production.
// - Minification
// - Concatenation
// - Debug stripping

gulp.task('production', ['clean'], function() {

    // Styles
    var styles = gulp.src(paths.assets.styles.files)
        .pipe(sass())
        .pipe(autoprefix(settings.autoprefix.versions))
        .pipe(minify())
        .pipe(gulp.dest(paths.public.styles));

    // Scripts
    var scripts = gulp.src(paths.assets.js.files)
        .pipe(concat('main.js'))
        .pipe(strip())
        .pipe(uglify())
        .pipe(gulp.dest(paths.public.js));

    // Images.
    var imgs = gulp.src(paths.assets.img.files)
        .pipe(img()).pipe(gulp.dest(paths.public.img));

    // Return the streams in one combined stream
    return merge(styles, scripts, imgs);
});

// Deployment
// ==========
// This task runs 'production' and then grabs all the files
// we want to upload and puts them in there own folder.

gulp.task('deploy', ['production'], function() {
    gulp.src(deployment.files, { base: '.' })
        .pipe(gulp.dest(deployment.destination));
});

//
// Default
// =======
// Runs every task, and then watches the project  for changes.

gulp.task('default', ['clean', 'styles', 'scripts', 'images', 'watch'], function() {
    notifier.notify({ message: 'Tasks complete' });
});<commit_msg>Update ingored files for deploy script<commit_after>// Dependencies
// ============

var gulp = require('gulp'),

    // Styles
    sass = require('gulp-sass'),
    autoprefix = require('gulp-autoprefixer'),
    minify = require('gulp-minify-css'),

    // Scripts
    uglify = require('gulp-uglify'),
    strip = require('gulp-strip-debug'),
    concat = require('gulp-concat'),

    // Images
    img = require('gulp-imagemin'),
    cache = require('gulp-cache'),

    // Other
    util = require('gulp-util'),
    del = require('del'),
    notify = require('gulp-notify'),
    notifier = require('node-notifier'),
    merge = require('merge-stream');

// Assets
// ======

var paths = {
    assets: {
        styles: {
            dir: 'assets/styles',
            files: 'assets/styles/**/*.scss',
        },
        js: {
            dir: 'assets/scripts/',
            files: [
                'assets/scripts/vendor/**/*.js',
                'assets/scripts/src/**/*.js',
                'assets/scripts/main.js'
            ],
        },
        img: {
            dir: 'assets/images',
            files: 'assets/images/**/*'
        }
    },
    public: {
        styles: 'public/styles',
        js: 'public/scripts',
        img: 'public/images',
    }
}

// General Settings
// ================

var settings = {
    autoprefix: {
        versions: 'last 4 version'
    }
}

// Deployment
// ==========

var deployment = {

    // The files we want to deploy
    files: [
        '**/*',
        '!{_deploy,_deploy/**}',
        '!{assets,assets/**}',
        '!{node_modules,node_modules/**}',
        '!package.json',
        '!gulpfile.js',
        '!readme.md',
        '!LICENSE.md',
        '!yarn.lock'
    ],

    // The folder to store them in
    destination: '_deploy'
}

// Styles
// ======
// Grabs everything inside the styles & sprites
// directories, concantinates and compiles scss,
// builds sprites, and then outputs them to their
// respective target directories.

gulp.task('styles', function() {
    gulp.src(paths.assets.styles.files)
        .pipe(sass())
        .pipe(autoprefix(settings.autoprefix.versions))
        .pipe(gulp.dest(paths.public.styles));
});

// Scripts
// =======
// Grabs everything inside the js directory,
// concantinates and minifies, and then outputs
// them to the target directory.

gulp.task('scripts', function() {
    gulp.src(paths.assets.js.files)
        .pipe(concat('main.js'))
        .pipe(gulp.dest(paths.public.js));
});

// Images
// ======
// Grabs everything inside the img directory,
// optimises each image, and then outputs them to
// the target directory.

gulp.task('images', function() {
    gulp.src(paths.assets.img.files)
        .pipe(gulp.dest(paths.public.img));
});

// Cache-buster
// ============
// Completely clear the cache to stop image-min
// outputting oncorrect image names etc.

gulp.task('clear', function(done) {
    return cache.clearAll(done);
});

// Cleaner
// =======
// Deletes all the public asset folders.

gulp.task('clean', function() {
    return del([
        paths.public.styles,
        paths.public.js,
        paths.public.img
    ]);
});

// Watcher
// =======
// Watches the different directores for changes and then
// runs their relevant tasks and livereloads.

gulp.task('watch', function() {
    // Run the appropriate task when assets change
    gulp.watch(paths.assets.styles.files, ['styles']);
    gulp.watch(paths.assets.js.files, ['scripts']);
    gulp.watch(paths.assets.img.files, ['images']);
});

// Production assets
// =================
// Goes through all our assets and readies them for production.
// - Minification
// - Concatenation
// - Debug stripping

gulp.task('production', ['clean'], function() {

    // Styles
    var styles = gulp.src(paths.assets.styles.files)
        .pipe(sass())
        .pipe(autoprefix(settings.autoprefix.versions))
        .pipe(minify())
        .pipe(gulp.dest(paths.public.styles));

    // Scripts
    var scripts = gulp.src(paths.assets.js.files)
        .pipe(concat('main.js'))
        .pipe(strip())
        .pipe(uglify())
        .pipe(gulp.dest(paths.public.js));

    // Images.
    var imgs = gulp.src(paths.assets.img.files)
        .pipe(img()).pipe(gulp.dest(paths.public.img));

    // Return the streams in one combined stream
    return merge(styles, scripts, imgs);
});

// Deployment
// ==========
// This task runs 'production' and then grabs all the files
// we want to upload and puts them in there own folder.

gulp.task('deploy', ['production'], function() {
    gulp.src(deployment.files, { base: '.' })
        .pipe(gulp.dest(deployment.destination));
});

//
// Default
// =======
// Runs every task, and then watches the project  for changes.

gulp.task('default', ['clean', 'styles', 'scripts', 'images', 'watch'], function() {
    notifier.notify({ message: 'Tasks complete' });
});<|endoftext|>


<commit_before>var assert = require('assert'),
    parse = require('../lib/irc2/parser/command-parser');

assert.deepEqual(parse(':lindbohm.freenode.net NOTICE * :*** Found your hostname'), {
  prefix: 'lindbohm.freenode.net',
  command: 'NOTICE',
  middle: ['*'],
  trailing: '*** Found your hostname'
});

assert.deepEqual(parse('PING :pratchett.freenode.net'), {
  prefix: null,
  command: 'PING',
  middle: [],
  trailing: 'pratchett.freenode.net'
});

assert.deepEqual(parse(':barjavel.freenode.net 372 mmalecki__ :- the network!'), {
  prefix: 'barjavel.freenode.net',
  command: '372',
  middle: ['mmalecki__'],
  trailing: '- the network!'
});

assert.deepEqual(parse(':source 372 many middle :- the network!'), {
  prefix: 'source',
  command: '372',
  middle: ['many', 'middle'],
  trailing: '- the network!'
});

assert.deepEqual(parse(':source 372 many middle'), {
  prefix: 'source',
  command: '372',
  middle: ['many', 'middle'],
  trailing: null
});

assert.deepEqual(parse(':source 372 many middle :with trailing'), {
  prefix: 'source',
  command: '372',
  middle: ['many', 'middle'],
  trailing: 'with trailing'
});
<commit_msg>[test] `irc2` -> `ircb`<commit_after>var assert = require('assert'),
    parse = require('../lib/ircb/parser/command-parser');

assert.deepEqual(parse(':lindbohm.freenode.net NOTICE * :*** Found your hostname'), {
  prefix: 'lindbohm.freenode.net',
  command: 'NOTICE',
  middle: ['*'],
  trailing: '*** Found your hostname'
});

assert.deepEqual(parse('PING :pratchett.freenode.net'), {
  prefix: null,
  command: 'PING',
  middle: [],
  trailing: 'pratchett.freenode.net'
});

assert.deepEqual(parse(':barjavel.freenode.net 372 mmalecki__ :- the network!'), {
  prefix: 'barjavel.freenode.net',
  command: '372',
  middle: ['mmalecki__'],
  trailing: '- the network!'
});

assert.deepEqual(parse(':source 372 many middle :- the network!'), {
  prefix: 'source',
  command: '372',
  middle: ['many', 'middle'],
  trailing: '- the network!'
});

assert.deepEqual(parse(':source 372 many middle'), {
  prefix: 'source',
  command: '372',
  middle: ['many', 'middle'],
  trailing: null
});

assert.deepEqual(parse(':source 372 many middle :with trailing'), {
  prefix: 'source',
  command: '372',
  middle: ['many', 'middle'],
  trailing: 'with trailing'
});
<|endoftext|>


<commit_before>/*global angular, alert, confirm*/
/*jslint nomen: true, es5: true */
angular.module('admin').directive('locationItem', ['Admin', '$document', '$timeout', 'Devices', 'ActionResultDialogService', function (Admin, $document, $timeout, Devices, ActionResultDialogService) {
    'use strict';

    var template = '
';
    template += '{{location.name}}';
    template += '<input class="location-item-edit" type="text" placeholder="New location" ng-show="editMode" ng-model="location.name" focus-on="editMode" select-on="editMode" />';
    template += '';
    template += '';
    template += '
'

    function link(scope, element, attrs) {
        var ensureReadOnlyMode = function () {
            if (scope.editMode) {
                scope.editMode = false;
                scope.$emit('locationNotEdited');
            }
        };

        var rememberActualLocationName = function () {
            scope.locationNameOriginalValue = scope.location.name;
        };

        var formatDevicesNamesToCommaSeparatedString = function (devices) {
            var res = '',
                device;

            res = devices.map(function (device) {return device.name; }).join(", ");

            return res;
        };

        scope.editMode = false;
        rememberActualLocationName();

        if (!scope.location._id) {
            scope.editMode = true;
            scope.$emit('locationEdited');
        }

        scope.editLocation = function () {
            if (!scope.editEnabled()) {
                return;
            }

            if (!scope.editMode) {
                scope.editMode = true;
                scope.$emit('locationEdited');
                $timeout(function () {
                    scope.$apply();
                });
            }
        };

        scope.deleteLocation = function (event) {
            if (event) {
                event.stopPropagation();
            }

            if (scope.editMode) {
                ensureReadOnlyMode();
            }

            if (!scope.location._id) {
                scope.$emit('locationAddCanceled', scope.location);
                return;
            }

            Devices.getByLocationName({locationName: scope.location.name}, function (devices) {
                var msg,
                    adminService;

                if (devices.length > 0) {
                    msg = 'Delete is not allowed because the devices from below are attached to the location. Please change the location of the devices.\r\n' + formatDevicesNamesToCommaSeparatedString(devices);
                    alert(msg);
                    return;
                }

                adminService = new Admin(scope.location);
                adminService.$deleteLocation();
                scope.$emit('locationDeleted');
            });
        };

        scope.saveLocation = function (event) {
            var adminService = new Admin(scope.location);

            if (event) {
                event.stopPropagation();
            }

            if (!scope.editMode) {
                return;
            }

            if (!scope.location.name) {
                ActionResultDialogService.showOkDialog('The location must have a name!', scope);
                return;
            }

            if (!scope.isLocationNameUnique({location: scope.location})) {
                ActionResultDialogService.showOkDialog('The location name must be unique!', scope);
                return;
            }

            if (scope.locationNameOriginalValue === scope.location.name) {
                ensureReadOnlyMode();
                return;
            }

            if (scope.location._id) {
                Devices.getByLocationName({ locationName: scope.locationNameOriginalValue }, function (devices) {
                    if (devices.length !== 0) {
                        var msg = 'There are devices attached to the location. Please confirm that the devices locations will be updated. The attached devices: ' + formatDevicesNamesToCommaSeparatedString(devices);
                        if (confirm(msg) === false) {
                            ensureReadOnlyMode();
                            return;
                        }
                    }

                    adminService.$updateLocation(function () {
                        rememberActualLocationName();
                        ensureReadOnlyMode();
                    });
                });
            } else {
                adminService.$saveLocation(function (savedLocation) {
                    scope.location._id = savedLocation._id;
                    rememberActualLocationName();
                    ensureReadOnlyMode();
                });
            }
        };

        var keyDownHandler = function (event) {
            if (!scope.editMode) {
                return;
            }

            switch (event.keyCode) {
                case 13: // enter
                    event.preventDefault();
                    scope.saveLocation();
                    break;

                case 27: // escape
                    event.preventDefault();
                    ensureReadOnlyMode();
                    if (scope.location._id) {
                        scope.location.name = scope.locationNameOriginalValue;
                    } else {
                        scope.$emit('locationAddCanceled', scope.location);
                    }
                    break;
            }
        };

        element.on('keydown', keyDownHandler);

        scope.$on("$destroy", function () {
            element.off('keydown', keyDownHandler);
        });
    }

    return {
        restrict: 'A',
        link: link,
        transclude: true,
        template: template,
        scope: {
            location: '=',
            isLocationNameUnique: '&',
            editEnabled: '&'
        }
    };
}]);
<commit_msg>Add page leave confirmation dialog to the locations page. [IQSLDSH-370]<commit_after>/*global angular, alert, confirm*/
/*jslint nomen: true, es5: true */
angular.module('admin').directive('locationItem', ['Admin', '$document', '$timeout', 'Devices', 'ActionResultDialogService', function (Admin, $document, $timeout, Devices, ActionResultDialogService) {
    'use strict';

    var template = '
';
    template += '{{location.name}}';
    template += '<input class="location-item-edit" type="text" placeholder="New location" ng-show="editMode" ng-model="location.name" focus-on="editMode" select-on="editMode" />';
    template += '';
    template += '';
    template += '
'

    function link(scope, element, attrs) {
        var ensureReadOnlyMode = function () {
            if (scope.editMode) {
                scope.editMode = false;
                scope.$emit('locationNotEdited');
            }
        };

        var rememberActualLocationName = function () {
            scope.locationNameOriginalValue = scope.location.name;
        };

        var formatDevicesNamesToCommaSeparatedString = function (devices) {
            var res = '',
                device;

            res = devices.map(function (device) {return device.name; }).join(", ");

            return res;
        };

        scope.editMode = false;
        rememberActualLocationName();

        if (!scope.location._id) {
            scope.editMode = true;
            scope.$emit('locationEdited');
        }

        scope.editLocation = function () {
            if (!scope.editEnabled()) {
                return;
            }

            if (!scope.editMode) {
                scope.editMode = true;
                scope.$emit('locationEdited');
                $timeout(function () {
                    scope.$apply();
                });
            }
        };

        scope.deleteLocation = function (event) {
            if (event) {
                event.stopPropagation();
            }

            if (scope.editMode) {
                ensureReadOnlyMode();
            }

            if (!scope.location._id) {
                scope.$emit('locationAddCanceled', scope.location);
                return;
            }

            Devices.getByLocationName({locationName: scope.location.name}, function (devices) {
                var msg,
                    adminService;

                if (devices.length > 0) {
                    msg = 'Delete is not allowed because the devices from below are attached to the location. Please change the location of the devices.\r\n' + formatDevicesNamesToCommaSeparatedString(devices);
                    alert(msg);
                    return;
                }

                adminService = new Admin(scope.location);
                adminService.$deleteLocation();
                scope.$emit('locationDeleted');
            });
        };

        scope.saveLocation = function (event) {
            var adminService = new Admin(scope.location);

            if (event) {
                event.stopPropagation();
            }

            if (!scope.editMode) {
                return;
            }

            if (!scope.location.name) {
                ActionResultDialogService.showOkDialog('The location must have a name!', scope);
                return;
            }

            if (!scope.isLocationNameUnique({location: scope.location})) {
                ActionResultDialogService.showOkDialog('The location name must be unique!', scope);
                return;
            }

            if (scope.locationNameOriginalValue === scope.location.name) {
                ensureReadOnlyMode();
                return;
            }

            if (scope.location._id) {
                Devices.getByLocationName({ locationName: scope.locationNameOriginalValue }, function (devices) {
                    if (devices.length !== 0) {
                        var msg = 'There are devices attached to the location. Please confirm that the devices locations will be updated. The attached devices: ' + formatDevicesNamesToCommaSeparatedString(devices);
                        if (confirm(msg) === false) {
                            ensureReadOnlyMode();
                            return;
                        }
                    }

                    adminService.$updateLocation(function () {
                        rememberActualLocationName();
                        ensureReadOnlyMode();
                    });
                });
            } else {
                adminService.$saveLocation(function (savedLocation) {
                    scope.location._id = savedLocation._id;
                    rememberActualLocationName();
                    ensureReadOnlyMode();
                });
            }
        };

        var keyDownHandler = function (event) {
            if (!scope.editMode) {
                return;
            }

            switch (event.keyCode) {
                case 13: // enter
                    event.preventDefault();
                    scope.saveLocation();
                    break;

                case 27: // escape
                    event.preventDefault();
                    ensureReadOnlyMode();
                    if (scope.location._id) {
                        scope.location.name = scope.locationNameOriginalValue;
                    } else {
                        scope.$emit('locationAddCanceled', scope.location);
                    }
                    break;
            }
        };

        element.on('keydown', keyDownHandler);

        scope.$on("$destroy", function () {
            element.off('keydown', keyDownHandler);
        });

        scope.$on('$stateChangeStart', function (event) {
            if (!scope.editMode) {
                return;
            }

            var msg = "The locations were changed. Are you sure you want to leave this page?";
            var answer = confirm(msg);

            if (!answer) {
                event.preventDefault();
            }
        });
    }

    return {
        restrict: 'A',
        link: link,
        transclude: true,
        template: template,
        scope: {
            location: '=',
            isLocationNameUnique: '&',
            editEnabled: '&'
        }
    };
}]);
<|endoftext|>


<commit_before>import * as r from 'rethinkdb'

export const setup = () => {
  // r.connect({host: process.env.RDB_HOST, port: process.env.RDB_PORT}, (err, conn) => {
  r.connect({host: process.env.RDB_HOST}, (err, conn) => {
    if (err) {
      console.log(`Failed to connect to baton database! ${err}`)
      return
    }

    // r.dbDrop('baton').run(conn)

    r.dbCreate('baton').run(conn, (err) => {
      if (err) return // ignore, only needs to be run once

      r.db('baton').tableCreate('batons').run(conn, (err, result) => {
        if (err) return // ignore, only needs to be run once

        console.log(JSON.stringify(result, null, 2))
      })
    })
  })
}

// creates promise wrappers for single and collection db entities
export const runPromise = {
  one: (resolve, reject) => {
    return (err, baton) => {
      if (!err) {
        console.log('[baton] Fetched baton by id', id, baton)
        resolve(baton)
      } else {
        console.log(`[baton] Failed to acquire baton ${id}: ${err}`)
        reject(err)
      }
    }
  },

  all: (resolve, reject) => {
    return (err, batons) => {
      if (err) {
        console.log(`[baton] Failed to acquire batons ${err}`)
        reject(err)
      }

      batons.toArray()
        .then(resolve)
        .error(reject)
    }
  }
}
<commit_msg>:wrench: drop db on build (since only 1 instance)<commit_after>import * as r from 'rethinkdb'

export const setup = () => {
  // r.connect({host: process.env.RDB_HOST, port: process.env.RDB_PORT}, (err, conn) => {
  r.connect({host: process.env.RDB_HOST}, (err, conn) => {
    if (err) {
      console.log(`Failed to connect to baton database! ${err}`)
      return
    }

    r.dbDrop('baton').run(conn)

    r.dbCreate('baton').run(conn, (err) => {
      if (err) return // ignore, only needs to be run once

      r.db('baton').tableCreate('batons').run(conn, (err, result) => {
        if (err) return // ignore, only needs to be run once

        console.log(JSON.stringify(result, null, 2))
      })
    })
  })
}

// creates promise wrappers for single and collection db entities
export const runPromise = {
  one: (resolve, reject) => {
    return (err, baton) => {
      if (!err) {
        console.log('[baton] Fetched baton by id', id, baton)
        resolve(baton)
      } else {
        console.log(`[baton] Failed to acquire baton ${id}: ${err}`)
        reject(err)
      }
    }
  },

  all: (resolve, reject) => {
    return (err, batons) => {
      if (err) {
        console.log(`[baton] Failed to acquire batons ${err}`)
        reject(err)
      }

      batons.toArray()
        .then(resolve)
        .error(reject)
    }
  }
}
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var q = require('q');
// Our lib:
var examples = require('./examples');
var handle = require('./convert').handle;
// Our utils:
var osta = require('./server/osta');
var ssr = require('./server/ssr');
var httpUtils = require('./server/http-utils');
var httpGet = httpUtils.httpGet;
var jsonApiPromise = httpUtils.jsonApiPromise;
var fetch = httpUtils.fetch;
var cache = require('./server/cache');
var diff = require('diff').diffJson;

// Vars:
var base = "https://inschrijven.schaatsen.nl/api/";
var vantage = "http://emandovantage.com/api/";
var excelPattern = vantage+"competitions/:id/reports/Results/5";
var ostaPattern = "http://www.osta.nl/?ZoekStr=:q"
var ssrPattern = "http://speedskatingresults.com/api/json/skater_lookup?familyname=:ln&givenname=:fn"
var ssrProfilePattern = "http://speedskatingresults.com/index.php?p=17&s=:sid"
var ssrSeasonBestPattern = "http://speedskatingresults.com/api/json/season_bests.php?skater=:sid&start=:start&end=:end"
var ssrCompetitonsPattern = "http://speedskatingresults.com/api/json/skater_competitions.php?skater=:sid&season=:season"
var ssrCompetitonPattern = "http://speedskatingresults.com/index.php?p=6&e=:cid"
var ostaTimesPattern = "http://www.osta.nl/?pid=:pid&Seizoen=ALL&Afstand=&perAfstand=0"
var ostaRitPattern = "http://www.osta.nl/rit.php?ID=:rid"

var competitionsPromise = () => fetch(base+"competitions", { dataType: 'json', cache: { key: "competitions", postfix: '.json', expired: cache.maxAge(5,'m') }});
var competitionPromise = (id) => fetch(base+"competitions/:id".replace(":id", id), { dataType: 'json', cache: { key: "competition:"+id, postfix: '.api.json', expired: cache.maxAge(5,'m') } });

function onError(e) {
	this.send(500, e.stack.replace(/\n/g, "\n
").replace(/\s/g, " ").replace(/\t/g, "    "));
}

// List of competitions
app.get('/api/competitions', function (req, res) {
	res.type('json');
	competitionsPromise()
		.then(l => l.map(simplifyCompetition))
		.then(l => res.json(l))
		.fail(onError.bind(res));
});

// Single competition with more detail
app.get('/api/competitions/:id', function (req, res) {
	res.type('json');
	competitionPromise(req.params.id).then(obj => {
		res.json(obj);
	}).fail(onError.bind(res));
});

// Resulting times from a competition
app.get('/api/competitions/:id/result', function (req, res) {
	const id = req.params.id;
	cache("results:"+id, { postfix: '.json', expired: cache.maxAge(5,'m') }, () => {
		return httpUtils
			// Fetch XLSX
			.fetch(excelPattern.replace(":id", id), { dataType: 'binary', cache: { encoding: 'binary', key: 'xlsx:'+id, postfix: '.xlsx'  } })
			// Parse XLSX to result JSON output
			.then(data => q.nfcall(handle, data.toString('binary'), {base64: false, checkCRC32: true}))
			// Prepare for json file storage
			.then(data => new Buffer(JSON.stringify(data), 'utf8'));
	})
	.then(times => res.json(JSON.parse(times)))
	.fail(onError.bind(res));
});

// Query linkable services to user name and birthdate
app.get('/api/skaters/find', function (req, res){
	const name = req.query.first_name + " " + req.query.last_name;
	const id = JSON.stringify([ req.query.first_name, req.query.last_name, req.query.birthdate ]);

	const osta_url = ostaPattern.replace(":q", name);
	const p_osta = httpUtils
		.fetch(osta_url, { cache: { key: "osta."+id, postfix: '.osta.html', expired: cache.maxAge(10, 'd') } })
		.then(osta.parseSearch);

	const ssr_url = ssrPattern.replace(':ln', req.query.last_name).replace(':fn', req.query.first_name);
	const p_ssr = httpUtils
		.fetch(ssr_url, { cache: { key: "ssr."+id, postfix: '.ssr.json', expired: cache.maxAge(10, 'd') } })
	 	.then(ssr.parseSearch);

	q.all([p_osta, p_ssr])
 	  .then(result => res.json([].concat.apply([], result)))
	  .fail(onError.bind(res));
});

// Query skate result times from Osta
app.get('/api/skaters/osta/:pid', function (req, res){
	const pid = req.params.pid;

	if(req.query.rid) {
		const rid = req.query.rid;
		var validate = (data) => {
			if(data.indexOf("Geen rit informatie opgevraagd.") < 0) return true;
			throw new Error("404 - invalid RID");
		};

		httpUtils
			.fetch(ostaRitPattern.replace(":rid", rid), { validate, cache: { key: "osta.rit:"+rid, postfix: '.osta.html', expired: cache.maxAge(365, 'd') } })
			.then(osta.parseRaceDetail)
			.then(detail => res.json({
				times: detail,
				more: []
			}))
			.fail(onError.bind(res));
			return;
	}

	var validate = (data) => {
		if(data.indexOf('class="seizoen"') >= 0)
			return true;
		throw new Error("404 - id not found");
	};

	httpUtils
		.fetch(ostaTimesPattern.replace(":pid", pid), { validate, cache: { key: "osta.times:"+pid, postfix: '.osta.html', expired: cache.maxAge(1, 'd') } })
		.then(osta.parsePersonTimes)
		.then(times => res.json({
			times: times,
			more: times.filter(t => t.osta_rid).map(t => req.url + "?rid=" + t.osta_rid)
		}))
		.fail(onError.bind(res));
});

// Query skate result times from SSR
app.get('/api/skaters/ssr/:sid', function (req, res){
	const sid = parseInt(req.params.sid);
	const start = ssr.firstYear;
	const end = ssr.currentSeason();
	var fill = (str) => str.replace(":sid", sid).replace(":start", start).replace(":end", end).replace(":season", req.query.season);

	// Parse HTML competition rankings
	if(req.query.competition) {
		const c404 = "Competition not found";
		const url = ssrCompetitonPattern.replace(":cid", req.query.competition);

		// Retrieve profile for name
		var profile = httpUtils.fetch(fill(ssrProfilePattern), { dataType: 'html', cache: { key: "ssr.profile"+sid, postfix: '.ssr.profile.html', expired: cache.maxAge(365, 'd') } })
			.then(ssr.parseProfile);

		// Retrieve full rankings
		var ranks = httpUtils
			.fetch(url, { dataType: 'html', cache: { postfix: '.ssr.comp.html', expired: cache.maxAge(365, 'd') } })
			.then(ssr.parseRanks);

		q.all([ranks, profile])
		  .spread((ranks, profile) => {
				res.json({
					times: ranks.filter(r => r.name == profile.name).sort((a,b) => a.ssr_ranking - b.ssr_ranking),
					more: []
				});
			}).fail(onError.bind(res));
	}
	// Retrieve per season competition list
	else if(req.query.season) {
		var comps = httpUtils.fetch(fill(ssrCompetitonsPattern), { dataType: 'json', cache: { postfix: '.ssr.comps.json', expired: cache.maxAge(1, 'd') } })
		comps.then(data => {
			res.json({
				competitions: data.competitions,
				more: data.competitions.map(comp => req.url + "&competition=" + comp.id)
			});
		}).fail(onError.bind(res));
	}
	// Retrieve all seasons the user skated after 2006, and fastest times
	else {
		var validate = (data) => {
			if(data instanceof Buffer) data = data.toString();
			if(typeof data == 'string') data = JSON.parse(data);
			if(data.seasons && data.seasons.length > 0) return true;
			throw new Error("404 - skater not found");
		};

		var profile = httpUtils.fetch(fill(ssrProfilePattern), { dataType: 'html', cache: { key: "ssr.profile"+sid, postfix: '.ssr.profile.html', expired: cache.maxAge(365, 'd') } })
			.then(ssr.parseProfile);
		var sbs = httpUtils.fetch(fill(ssrSeasonBestPattern), { validate, dataType: 'json', cache: { key: "ssr.sbs:"+sid, postfix: '.ssr.sbs.json', expired: cache.maxAge(1, 'd') } })

		q.all([profile, sbs])
			.spread((profile, data) => ssr.parseSeasonBests(data, profile.name))
			.then(data => {
				data.more = data.seasons.map(season => req.url + "?season=" + season);
				res.json(data);
			})
			.fail(onError.bind(res));
	}

});

app.use('/', express.static(__dirname + '/web'));

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Converter server listening at http://%s:%s', host, port);
});

var allowed = ["discipline", "starts", "ends", "name", "id", "location", "resultsStatus", "venue"];
function simplifyCompetition(comp){
	Object.keys(comp)
		.filter(key => allowed.indexOf(key) == -1)
		.forEach(key => delete comp[key]);
	return comp;
}<commit_msg>Fix unused not included package by removal<commit_after>var express = require('express');
var app = express();
var q = require('q');
// Our lib:
var examples = require('./examples');
var handle = require('./convert').handle;
// Our utils:
var osta = require('./server/osta');
var ssr = require('./server/ssr');
var httpUtils = require('./server/http-utils');
var httpGet = httpUtils.httpGet;
var jsonApiPromise = httpUtils.jsonApiPromise;
var fetch = httpUtils.fetch;
var cache = require('./server/cache');

// Vars:
var base = "https://inschrijven.schaatsen.nl/api/";
var vantage = "http://emandovantage.com/api/";
var excelPattern = vantage+"competitions/:id/reports/Results/5";
var ostaPattern = "http://www.osta.nl/?ZoekStr=:q"
var ssrPattern = "http://speedskatingresults.com/api/json/skater_lookup?familyname=:ln&givenname=:fn"
var ssrProfilePattern = "http://speedskatingresults.com/index.php?p=17&s=:sid"
var ssrSeasonBestPattern = "http://speedskatingresults.com/api/json/season_bests.php?skater=:sid&start=:start&end=:end"
var ssrCompetitonsPattern = "http://speedskatingresults.com/api/json/skater_competitions.php?skater=:sid&season=:season"
var ssrCompetitonPattern = "http://speedskatingresults.com/index.php?p=6&e=:cid"
var ostaTimesPattern = "http://www.osta.nl/?pid=:pid&Seizoen=ALL&Afstand=&perAfstand=0"
var ostaRitPattern = "http://www.osta.nl/rit.php?ID=:rid"

var competitionsPromise = () => fetch(base+"competitions", { dataType: 'json', cache: { key: "competitions", postfix: '.json', expired: cache.maxAge(5,'m') }});
var competitionPromise = (id) => fetch(base+"competitions/:id".replace(":id", id), { dataType: 'json', cache: { key: "competition:"+id, postfix: '.api.json', expired: cache.maxAge(5,'m') } });

function onError(e) {
	this.send(500, e.stack.replace(/\n/g, "\n
").replace(/\s/g, " ").replace(/\t/g, "    "));
}

// List of competitions
app.get('/api/competitions', function (req, res) {
	res.type('json');
	competitionsPromise()
		.then(l => l.map(simplifyCompetition))
		.then(l => res.json(l))
		.fail(onError.bind(res));
});

// Single competition with more detail
app.get('/api/competitions/:id', function (req, res) {
	res.type('json');
	competitionPromise(req.params.id).then(obj => {
		res.json(obj);
	}).fail(onError.bind(res));
});

// Resulting times from a competition
app.get('/api/competitions/:id/result', function (req, res) {
	const id = req.params.id;
	cache("results:"+id, { postfix: '.json', expired: cache.maxAge(5,'m') }, () => {
		return httpUtils
			// Fetch XLSX
			.fetch(excelPattern.replace(":id", id), { dataType: 'binary', cache: { encoding: 'binary', key: 'xlsx:'+id, postfix: '.xlsx'  } })
			// Parse XLSX to result JSON output
			.then(data => q.nfcall(handle, data.toString('binary'), {base64: false, checkCRC32: true}))
			// Prepare for json file storage
			.then(data => new Buffer(JSON.stringify(data), 'utf8'));
	})
	.then(times => res.json(JSON.parse(times)))
	.fail(onError.bind(res));
});

// Query linkable services to user name and birthdate
app.get('/api/skaters/find', function (req, res){
	const name = req.query.first_name + " " + req.query.last_name;
	const id = JSON.stringify([ req.query.first_name, req.query.last_name, req.query.birthdate ]);

	const osta_url = ostaPattern.replace(":q", name);
	const p_osta = httpUtils
		.fetch(osta_url, { cache: { key: "osta."+id, postfix: '.osta.html', expired: cache.maxAge(10, 'd') } })
		.then(osta.parseSearch);

	const ssr_url = ssrPattern.replace(':ln', req.query.last_name).replace(':fn', req.query.first_name);
	const p_ssr = httpUtils
		.fetch(ssr_url, { cache: { key: "ssr."+id, postfix: '.ssr.json', expired: cache.maxAge(10, 'd') } })
	 	.then(ssr.parseSearch);

	q.all([p_osta, p_ssr])
 	  .then(result => res.json([].concat.apply([], result)))
	  .fail(onError.bind(res));
});

// Query skate result times from Osta
app.get('/api/skaters/osta/:pid', function (req, res){
	const pid = req.params.pid;

	if(req.query.rid) {
		const rid = req.query.rid;
		var validate = (data) => {
			if(data.indexOf("Geen rit informatie opgevraagd.") < 0) return true;
			throw new Error("404 - invalid RID");
		};

		httpUtils
			.fetch(ostaRitPattern.replace(":rid", rid), { validate, cache: { key: "osta.rit:"+rid, postfix: '.osta.html', expired: cache.maxAge(365, 'd') } })
			.then(osta.parseRaceDetail)
			.then(detail => res.json({
				times: detail,
				more: []
			}))
			.fail(onError.bind(res));
			return;
	}

	var validate = (data) => {
		if(data.indexOf('class="seizoen"') >= 0)
			return true;
		throw new Error("404 - id not found");
	};

	httpUtils
		.fetch(ostaTimesPattern.replace(":pid", pid), { validate, cache: { key: "osta.times:"+pid, postfix: '.osta.html', expired: cache.maxAge(1, 'd') } })
		.then(osta.parsePersonTimes)
		.then(times => res.json({
			times: times,
			more: times.filter(t => t.osta_rid).map(t => req.url + "?rid=" + t.osta_rid)
		}))
		.fail(onError.bind(res));
});

// Query skate result times from SSR
app.get('/api/skaters/ssr/:sid', function (req, res){
	const sid = parseInt(req.params.sid);
	const start = ssr.firstYear;
	const end = ssr.currentSeason();
	var fill = (str) => str.replace(":sid", sid).replace(":start", start).replace(":end", end).replace(":season", req.query.season);

	// Parse HTML competition rankings
	if(req.query.competition) {
		const c404 = "Competition not found";
		const url = ssrCompetitonPattern.replace(":cid", req.query.competition);

		// Retrieve profile for name
		var profile = httpUtils.fetch(fill(ssrProfilePattern), { dataType: 'html', cache: { key: "ssr.profile"+sid, postfix: '.ssr.profile.html', expired: cache.maxAge(365, 'd') } })
			.then(ssr.parseProfile);

		// Retrieve full rankings
		var ranks = httpUtils
			.fetch(url, { dataType: 'html', cache: { postfix: '.ssr.comp.html', expired: cache.maxAge(365, 'd') } })
			.then(ssr.parseRanks);

		q.all([ranks, profile])
		  .spread((ranks, profile) => {
				res.json({
					times: ranks.filter(r => r.name == profile.name).sort((a,b) => a.ssr_ranking - b.ssr_ranking),
					more: []
				});
			}).fail(onError.bind(res));
	}
	// Retrieve per season competition list
	else if(req.query.season) {
		var comps = httpUtils.fetch(fill(ssrCompetitonsPattern), { dataType: 'json', cache: { postfix: '.ssr.comps.json', expired: cache.maxAge(1, 'd') } })
		comps.then(data => {
			res.json({
				competitions: data.competitions,
				more: data.competitions.map(comp => req.url + "&competition=" + comp.id)
			});
		}).fail(onError.bind(res));
	}
	// Retrieve all seasons the user skated after 2006, and fastest times
	else {
		var validate = (data) => {
			if(data instanceof Buffer) data = data.toString();
			if(typeof data == 'string') data = JSON.parse(data);
			if(data.seasons && data.seasons.length > 0) return true;
			throw new Error("404 - skater not found");
		};

		var profile = httpUtils.fetch(fill(ssrProfilePattern), { dataType: 'html', cache: { key: "ssr.profile"+sid, postfix: '.ssr.profile.html', expired: cache.maxAge(365, 'd') } })
			.then(ssr.parseProfile);
		var sbs = httpUtils.fetch(fill(ssrSeasonBestPattern), { validate, dataType: 'json', cache: { key: "ssr.sbs:"+sid, postfix: '.ssr.sbs.json', expired: cache.maxAge(1, 'd') } })

		q.all([profile, sbs])
			.spread((profile, data) => ssr.parseSeasonBests(data, profile.name))
			.then(data => {
				data.more = data.seasons.map(season => req.url + "?season=" + season);
				res.json(data);
			})
			.fail(onError.bind(res));
	}

});

app.use('/', express.static(__dirname + '/web'));

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Converter server listening at http://%s:%s', host, port);
});

var allowed = ["discipline", "starts", "ends", "name", "id", "location", "resultsStatus", "venue"];
function simplifyCompetition(comp){
	Object.keys(comp)
		.filter(key => allowed.indexOf(key) == -1)
		.forEach(key => delete comp[key]);
	return comp;
}<|endoftext|>


<commit_before>// all gulp tasks are located in the ./build/tasks directory
// gulp configuration is in files in ./build directory
require('require-dir')('build/tasks');
<commit_msg>Weekly menu added<commit_after>/// <binding ProjectOpened='watch' />
// all gulp tasks are located in the ./build/tasks directory
// gulp configuration is in files in ./build directory
require('require-dir')('build/tasks');
<|endoftext|>


<commit_before>define(['parse/parse',
        'khepri/compile/lexical',
        'khepri/lex/lexer',
        'khepri/parse/parser',
        'khepri/parse/expression_parser'],
function(parse,
        lexical,
        lexer,
        parser,
        expression){

    var testParser = function(stream) {
        return parser.parseStream(stream);
    };

    return {
        'module': "Lexical",
        'tests': [
            ["Simple Lexical",
            function(){
                var result = lexical.check(testParser(lexer.lex("var a; a; { a; };")));
                assert.ok(true);
            }],
            ["Simple undefined var Lexical",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("b; c;")));
                });
            }],
            ["Order",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("b; var b;")));
                });
            }],
            ["Outside of block",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("{ var b; }; b;")));
                });
            }],
            ["If body",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex(" if (true) var b; b;")));
                });
            }],
            ["Multiple in same scope",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("var a; var c; var a;")));
                });

                var result = lexical.check(testParser(lexer.lex("var a; { var a; }")));
                assert.ok(true);
            }],
        ],
    };
});
<commit_msg>Test for fail when multiple parameters with same name<commit_after>define(['parse/parse',
        'khepri/compile/lexical',
        'khepri/lex/lexer',
        'khepri/parse/parser',
        'khepri/parse/expression_parser'],
function(parse,
        lexical,
        lexer,
        parser,
        expression){

    var testParser = function(stream) {
        return parser.parseStream(stream);
    };

    return {
        'module': "Lexical",
        'tests': [
            ["Simple Lexical",
            function(){
                var result = lexical.check(testParser(lexer.lex("var a; a; { a; };")));
                assert.ok(true);
            }],
            ["Simple undefined var Lexical",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("b; c;")));
                });
            }],
            ["Order",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("b; var b;")));
                });
            }],
            ["Outside of block",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("{ var b; }; b;")));
                });
            }],
            ["If body",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex(" if (true) var b; b;")));
                });
            }],
            ["Multiple in same scope",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("var a; var c; var a;")));
                });

                var result = lexical.check(testParser(lexer.lex("var a; { var a; }")));
                assert.ok(true);
            }],

            ["Multiple parameter same name",
            function(){
                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("(\\x, x -> x*x)(2)")));
                });

                assert.throws(function(){
                    lexical.check(testParser(lexer.lex("(\\x, a, b, x -> x*x)(2)")));
                });
            }],
        ],
    };
});
<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const nconf = require('nconf');
const swig = require('swig');
const path = require('path');
const redis = require('redis');

nconf.argv().env().file({
    file: 'secrets.json'
});

// littlebits setup
const api = require('@littlebits/cloud-http')
    .defaults({
        access_token: nconf.get('cloudbit_access_token'),
        device_id: nconf.get('cloudbit_device_id')
    });

// express setup
const app = express();
app.set('views', path.join(__dirname, 'views'));
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.use(express.static(path.join(__dirname, 'public')));

// pubnub setup
var pubnub = require("pubnub")({
    ssl: true,
    publish_key: nconf.get('pubnub_publish_key'),
    subscribe_key: nconf.get('pubnub_subscribe_key')
});

pubnub.subscribe({
    channel: "party",
    callback: function(message) {
        console.log('someone decided to PAARTY!');
        api.output({ percent: 100, duration_ms: 500 });
    }
});

// set up redis
const redisClient = redis.createClient(
    nconf.get('redisPort') || '6379',
    nconf.get('redisHost') || '127.0.0.1',
    {
        'auth_pass': nconf.get('redisKey'),
        'return_buffers': true
    }
).on('error', function(err) {
    console.error('ERR:REDIS: ' + err);
});

// routes
app.get('/', function(req, res, next) {
    redisClient.get('clicks', function(err, data) {
        console.log("err: " + err);
        console.log("data: " + data);
        if (err) { return next(err); }
        res.render('index', {
            subscribeKey: nconf.get('pubnub_subscribe_key'),
            clicks: (data ? data : 0) + "" // swig type bug
        });
    });
});

app.get('/reset', function(req, res, next) {
    redisClient.set('clicks', 0, function(err, data) {
        if (err) { return next(err); }
        res.sendStatus(202);
    });
});

// increment the click counter in memcached
app.post('/click', function(req, res, next) {
    console.log("registering a click");
    redisClient.incr('clicks', function(err, reply) {
        if (err) return next(err);
        // broadcast the new click count to connected clients
        api.output();
        pubnub.publish({
            channel: 'click',
            message: reply,
            callback: function(r) {
                res.sendStatus(202);
            },
            error: function(err) {
                return next(err);
            }
        });
    });
});

// Start the server
const server = app.listen(process.env.PORT || 8080,
    '0.0.0.0', function() {
    console.log('App listening at http://%s:%s',
        server.address().address,
        server.address().port);
    console.log('Press Ctrl+C to quit.');
});
<commit_msg>cap votes to 100<commit_after>'use strict';

const express = require('express');
const nconf = require('nconf');
const swig = require('swig');
const path = require('path');
const redis = require('redis');

nconf.argv().env().file({
    file: 'secrets.json'
});

// littlebits setup
const api = require('@littlebits/cloud-http')
    .defaults({
        access_token: nconf.get('cloudbit_access_token'),
        device_id: nconf.get('cloudbit_device_id')
    });

// express setup
const app = express();
app.set('views', path.join(__dirname, 'views'));
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.use(express.static(path.join(__dirname, 'public')));

// pubnub setup
const pubnub = require("pubnub")({
    ssl: true,
    publish_key: nconf.get('pubnub_publish_key'),
    subscribe_key: nconf.get('pubnub_subscribe_key')
});

pubnub.subscribe({
    channel: "party",
    callback: function(message) {
        console.log('someone decided to PAARTY!');
        api.output({ percent: 100, duration_ms: 500 });
    }
});

// set up redis
const redisClient = redis.createClient(
    nconf.get('redisPort') || '6379',
    nconf.get('redisHost') || '127.0.0.1',
    {
        'auth_pass': nconf.get('redisKey'),
        'return_buffers': true
    }
).on('error', function(err) {
    console.error('ERR:REDIS: ' + err);
});

// routes
app.get('/', function(req, res, next) {
    redisClient.get('clicks', function(err, data) {
        console.log("err: " + err);
        console.log("data: " + data);
        let clicks = data ? data : 0;
        clicks = clicks > 100 ? 100 : clicks;
        if (err) { return next(err); }
        res.render('index', {
            subscribeKey: nconf.get('pubnub_subscribe_key'),
            clicks: clicks + "" // swig type bug
        });
    });
});

app.get('/reset', function(req, res, next) {
    redisClient.set('clicks', 0, function(err, data) {
        if (err) { return next(err); }
        res.sendStatus(202);
    });
});

// increment the click counter in memcached
app.post('/click', function(req, res, next) {
    console.log("registering a click");
    redisClient.incr('clicks', function(err, reply) {
        if (err) return next(err);
        // broadcast the new click count to connected clients
        let clicks = (reply > 100) ? 100 : reply;
        api.output();
        pubnub.publish({
            channel: 'click',
            message: clicks,
            callback: function(r) {
                res.sendStatus(202);
            },
            error: function(err) {
                return next(err);
            }
        });
    });
});

// Start the server
const server = app.listen(process.env.PORT || 8080,
    '0.0.0.0', function() {
    console.log('App listening at http://%s:%s',
        server.address().address,
        server.address().port);
    console.log('Press Ctrl+C to quit.');
});
<|endoftext|>


<commit_before>import React from 'react';
import sinon from 'sinon';
import expect from 'expect';
import TestUtils from 'react/lib/ReactTestUtils';
import AppFlux from '../../ui/flux';
import TaskList from '../../ui/components/TaskList';

import {makeTestContainer} from '../utils';

describe('task list', function() {
    it('handles a new task', function() {
        const flux = new AppFlux(),
              actions = flux.getActions("taskLists");

        const connect = function(el) { return el; };

        const list = {
            name: "testing",
            tasks: [
            ]
        };

        const TaskListContext = makeTestContainer(TaskList);

        const root = TestUtils.renderIntoDocument(
                <TaskListContext flux={flux}
                                 list={list}
                                 isOver={false}
                                 connectDropTarget={connect} />);

        const component = TestUtils.findRenderedComponentWithType(root, TaskList).decoratedComponentInstance;

        sinon.stub(actions, "createTask");

        component.refs.newTask.getInputDOMNode().value = "new task!";
        TestUtils.Simulate.submit(component.refs.newTaskForm.getDOMNode());
        expect(actions.createTask.calledOnce).toBe(true);

    });

    it('toggles edit mode', function() {

        const list = {
            id: 1,
            name: "testing",
            tasks: []
        };

        const flux = new AppFlux(),
              actions = flux.getActions("taskLists");

        const connect = function(el) { return el; };

        const TaskListContext = makeTestContainer(TaskList);

        const root = TestUtils.renderIntoDocument(
                <TaskListContext flux={flux}
                                 list={list}
                                 isOver={false}
                                 connectDropTarget={connect} />);

        const component = TestUtils.findRenderedComponentWithType(root, TaskList).decoratedComponentInstance;
        const h3 = TestUtils.findRenderedDOMComponentWithTag(component, "h3");
        const span = TestUtils.scryRenderedDOMComponentsWithTag(h3, "span")[1];

        sinon.stub(actions, "toggleTaskListEditMode");
        TestUtils.Simulate.click(span.getDOMNode());
        expect(actions.toggleTaskListEditMode.calledOnce).toBe(true);

    });

    it('renders a list with tasks', function() {

        const flux = new AppFlux();

        const connect = function(el) { return el; };

        const list = {
            id: 1,
            name: "testing",
            tasks: [
                {
                    text: "test1",
                    id: 1,
                    taskListId: 1
                }
            ]
        };

        const TaskListContext = makeTestContainer(TaskList);

        const component = TestUtils.renderIntoDocument(
                <TaskListContext flux={flux}
                                 list={list}
                                 isOver={false}
                                 connectDropTarget={connect} />
        );

    });
});

<commit_msg>Test fix<commit_after>import React from 'react';
import sinon from 'sinon';
import expect from 'expect';
import TestUtils from 'react/lib/ReactTestUtils';
import AppFlux from '../../ui/flux';
import TaskList from '../../ui/components/TaskList';

import {makeTestContainer} from '../utils';

describe('task list', function() {
    it('handles a new task', function() {
        const flux = new AppFlux(),
              actions = flux.getActions("taskLists");

        const connect = function(el) { return el; };

        const list = {
            name: "testing",
            tasks: [
            ]
        };

        const TaskListContext = makeTestContainer(TaskList);

        const root = TestUtils.renderIntoDocument(
                <TaskListContext flux={flux}
                                 list={list}
                                 isOver={false}
                                 connectDropTarget={connect} />);

        const component = TestUtils.findRenderedComponentWithType(root, TaskList).decoratedComponentInstance;
        const refs = component.decoratedComponentInstance.refs;

        sinon.stub(actions, "createTask");

        refs.newTask.getInputDOMNode().value = "new task!";
        TestUtils.Simulate.submit(refs.newTaskForm.getDOMNode());
        expect(actions.createTask.calledOnce).toBe(true);

    });

    it('toggles edit mode', function() {

        const list = {
            id: 1,
            name: "testing",
            tasks: []
        };

        const flux = new AppFlux(),
              actions = flux.getActions("taskLists");

        const connect = function(el) { return el; };

        const TaskListContext = makeTestContainer(TaskList);

        const root = TestUtils.renderIntoDocument(
                <TaskListContext flux={flux}
                                 list={list}
                                 isOver={false}
                                 connectDropTarget={connect} />);

        const component = TestUtils.findRenderedComponentWithType(root, TaskList).decoratedComponentInstance;
        const h3 = TestUtils.findRenderedDOMComponentWithTag(component, "h3");
        const span = TestUtils.scryRenderedDOMComponentsWithTag(h3, "span")[1];

        sinon.stub(actions, "toggleTaskListEditMode");
        TestUtils.Simulate.click(span.getDOMNode());
        expect(actions.toggleTaskListEditMode.calledOnce).toBe(true);

    });

    it('renders a list with tasks', function() {

        const flux = new AppFlux();

        const connect = function(el) { return el; };

        const list = {
            id: 1,
            name: "testing",
            tasks: [
                {
                    text: "test1",
                    id: 1,
                    taskListId: 1
                }
            ]
        };

        const TaskListContext = makeTestContainer(TaskList);

        const component = TestUtils.renderIntoDocument(
                <TaskListContext flux={flux}
                                 list={list}
                                 isOver={false}
                                 connectDropTarget={connect} />
        );

    });
});

<|endoftext|>