<commit_before>import { take, takeEvery, call, put } from 'redux-saga/effects';
import * as actions from '../actions/auth';
import { authActions } from '../actions/action-types.js';
import { storeAuthToken, deleteAuthToken } from '../helpers/auth';
import * as auth from '../fetch/auth';
import { browserHistory } from 'react-router';

/*
 * Listeners
 */
function* logout(action) {
  yield call(deleteAuthToken);
}

export function* watchSignUpRequest() {
  yield takeEvery(authActions.AUTH_SIGNUP_REQUEST, signUp);
}

export function* watchLoginRequest() {
  yield takeEvery(authActions.AUTH_LOGIN_REQUEST, authenticate);
}

export function* watchLogout() {
  yield takeEvery(authActions.AUTH_LOGOUT, logout);
}

/*
 * Workers
 */
function* signUp(action) {
  const { name, email, password } = action;
  let response = yield call(auth.signUp, name, email, password);

  switch (response.status) {
    case 200:
      yield put(actions.signUpSuccess());
      break;
    case 409:
      yield put(actions.signUpFail("Email is already in use"));
      break;
    default:
      yield put(actions.signUpFail("Sign up failed"));
  }
}

function* authenticate(action) {
  const { email, password} = action;
  const response = yield call(auth.authenticate, email, password);

  switch (response.status) {
    case 200: // OK
      // Rretrieve reponse body as json, save JWT for future requests and
      // dispatch action for succesful login and redirect app to root route.
      const body = yield call(() => response.json().then(data => data));
      yield call(storeAuthToken, body.token);
      yield put(actions.loginSuccess(body));
      yield call(browserHistory.push, '/');
      break;

    case 401: // Unauthorized
      yield put(actions.loginFail("Invalid email address or password"));
      break;

    default:
      yield put(actions.loginFail("Can't login"));
  }
}

<commit_msg>Reset typing test state when logging in<commit_after>import { take, takeEvery, call, put } from 'redux-saga/effects';
import * as actions from '../actions/auth';
import { reset } from '../actions/typing-test';
import { authActions } from '../actions/action-types.js';
import { storeAuthToken, deleteAuthToken } from '../helpers/auth';
import * as auth from '../fetch/auth';
import { browserHistory } from 'react-router';

/*
 * Listeners
 */
function* logout(action) {
  yield call(deleteAuthToken);
}

export function* watchSignUpRequest() {
  yield takeEvery(authActions.AUTH_SIGNUP_REQUEST, signUp);
}

export function* watchLoginRequest() {
  yield takeEvery(authActions.AUTH_LOGIN_REQUEST, authenticate);
}

export function* watchLogout() {
  yield takeEvery(authActions.AUTH_LOGOUT, logout);
}

/*
 * Workers
 */
function* signUp(action) {
  const { name, email, password } = action;
  let response = yield call(auth.signUp, name, email, password);

  switch (response.status) {
    case 200:
      yield put(actions.signUpSuccess());
      break;
    case 409:
      yield put(actions.signUpFail("Email is already in use"));
      break;
    default:
      yield put(actions.signUpFail("Sign up failed"));
  }
}

function* authenticate(action) {
  const { email, password} = action;
  const response = yield call(auth.authenticate, email, password);

  switch (response.status) {
    case 200: // OK
      // Rretrieve reponse body as json, save JWT for future requests and
      // dispatch action for succesful login and redirect app to root route.
      const body = yield call(() => response.json().then(data => data));
      yield call(storeAuthToken, body.token);
      yield put(actions.loginSuccess(body));
      yield put(reset());
      yield call(browserHistory.push, '/');
      break;

    case 401: // Unauthorized
      yield put(actions.loginFail("Invalid email address or password"));
      break;

    default:
      yield put(actions.loginFail("Can't login"));
  }
}
<|endoftext|>


<commit_before>var _ = require('lodash');
var desireds = require('./desireds');

var gruntConfig = {
        env: {
            test: {
                //CATALOG_API_TEST_SERVER: 'http://microservices-catalogapi-uparulek-142.mybluemix.net'
            }
        },

        mochaTest: {
            'server-side': {
                options: {
                    reporter: 'json',
                    clearRequireCache: true,
                    colors: true,
                    quite: true,
                    captureFile: 'tests/server/mochatest.json',
                    gruntLogHeader: false
                },
                src: ['tests/server/*.spec.js']
            },
            'server-side-spec': {
                options: {
                    reporter: 'spec',
                    clearRequireCache: true,
                    colors: true,
                    quite: true
                },
                src: ['tests/server/*.spec.js']
            },
            'fvt': {
                options: {
                    reporter: 'json',
                    clearRequireCache: true,
                    colors: true,
                    quite: true,
                    captureFile: 'tests/fvt/mochafvttest.json'
                },
                src: ['tests/fvt/*.spec.js']
            },
            'fvt-spec': {
                options: {
                    reporter: 'spec',
                    clearRequireCache: true,
                    colors: true,
                    quite: true
                },
                src: ['tests/fvt/*.spec.js']
            }
        },

        clean: {
            options: {
                force: true,
                expand: true
            },
            coverage: ['tests/server/coverage', 'tests/server/mochatest.json', 'tests/fvt/mochafvttest.json']
        },

        copy: {
            resourcesForInstrumented: {
                nonull: true,
                files: [{
                    expand: true,
                    dest: 'tests/server/coverage/instrumented',
                    src: ['routes/db.js']
                }]
            }
        },

        instrument: {
            files: ['routes/items.js'],
            options: {
                lazy: false,
                basePath: 'tests/server/coverage/instrumented/'
            }
        },

        storeCoverage: {
            options: {
                dir: 'tests/server/coverage/reports'
            }
        },

        makeReport: {
            src: 'tests/server/coverage/reports/*.json',
            options: {
                type: 'html',
                type: 'json-summary',
                dir: 'tests/server/coverage/reports',
                file: 'coverage-summary.json'
                //print: 'detail'
            }
        },

        simplemocha: {
            sauce: {
                options: {
                    timeout: 60000,
                    reporter: 'spec-xunit-file',
                },
                src: ['tests/sauce_actual/test-cases.js']
            },
            sauce_node: {
                options: {
                    timeout: 60000,
                    reporter: 'spec-xunit-file',
                },
                src: ['tests/sauce/test-cases.js']
            }
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            test: {
                options: {
                    jshintrc: 'test/.jshintrc'
                },
                src: ['test/*.js']
            },
        },
        concurrent: {
            'test-sauce': [], // dynamically filled
        },
        watch: {
            gruntfile: {
                files: '<%= jshint.gruntfile.src %>',
                tasks: ['jshint:gruntfile']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test']
            },
        }
    };

    _.forIn(desireds,function(desired, key) {
        gruntConfig.env[key] = {
            DESIRED: JSON.stringify(desired)
        };
        //gruntConfig.concurrent['test-sauce'].push('test:sauce:' + key);
    });

module.exports = function(grunt) {
	gruntConfig.pkg = grunt.file.readJSON('package.json');

    grunt.initConfig(gruntConfig);

    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-istanbul');
    grunt.loadNpmTasks('grunt-env');
    grunt.loadNpmTasks('grunt-simple-mocha');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('dev-test', ['env:test', 'clean:coverage', 'copy:resourcesForInstrumented', 'instrument', 'mochaTest:server-side-spec']);
    grunt.registerTask('dev-test-cov', ['env:test', 'clean:coverage', 'copy:resourcesForInstrumented', 'instrument', 'mochaTest:server-side', 'storeCoverage', 'makeReport']);
    grunt.registerTask('dev-fvtspec', ['env:test', 'clean:coverage', 'mochaTest:fvt-spec']);
    grunt.registerTask('dev-fvt', ['env:test', 'clean:coverage', 'mochaTest:fvt']);
    grunt.registerTask('test_real', ['env:chrome', 'simplemocha:sauce:' + _(desireds).keys().first()]);
    grunt.registerTask('test_fake', ['env:chrome', 'simplemocha:sauce_node:' + _(desireds).keys().first()]);
};
<commit_msg>Remove hardcoded app url for FVT tests.<commit_after>var _ = require('lodash');
var desireds = require('./desireds');

var gruntConfig = {
        env: {
            // dynamically filled
        },

        mochaTest: {
            'server-side': {
                options: {
                    reporter: 'json',
                    clearRequireCache: true,
                    colors: true,
                    quite: true,
                    captureFile: 'tests/server/mochatest.json',
                    gruntLogHeader: false
                },
                src: ['tests/server/*.spec.js']
            },
            'server-side-spec': {
                options: {
                    reporter: 'spec',
                    clearRequireCache: true,
                    colors: true,
                    quite: true
                },
                src: ['tests/server/*.spec.js']
            },
            'fvt': {
                options: {
                    reporter: 'json',
                    clearRequireCache: true,
                    colors: true,
                    quite: true,
                    captureFile: 'tests/fvt/mochafvttest.json'
                },
                src: ['tests/fvt/*.spec.js']
            },
            'fvt-spec': {
                options: {
                    reporter: 'spec',
                    clearRequireCache: true,
                    colors: true,
                    quite: true
                },
                src: ['tests/fvt/*.spec.js']
            }
        },

        clean: {
            options: {
                force: true,
                expand: true
            },
            coverage: ['tests/server/coverage', 'tests/server/mochatest.json', 'tests/fvt/mochafvttest.json']
        },

        copy: {
            resourcesForInstrumented: {
                nonull: true,
                files: [{
                    expand: true,
                    dest: 'tests/server/coverage/instrumented',
                    src: ['routes/db.js']
                }]
            }
        },

        instrument: {
            files: ['routes/items.js'],
            options: {
                lazy: false,
                basePath: 'tests/server/coverage/instrumented/'
            }
        },

        storeCoverage: {
            options: {
                dir: 'tests/server/coverage/reports'
            }
        },

        makeReport: {
            src: 'tests/server/coverage/reports/*.json',
            options: {
                type: 'html',
                type: 'json-summary',
                dir: 'tests/server/coverage/reports',
                file: 'coverage-summary.json'
                //print: 'detail'
            }
        },

        simplemocha: {
            sauce: {
                options: {
                    timeout: 60000,
                    reporter: 'spec-xunit-file',
                },
                src: ['tests/sauce_actual/test-cases.js']
            },
            sauce_node: {
                options: {
                    timeout: 60000,
                    reporter: 'spec-xunit-file',
                },
                src: ['tests/sauce/test-cases.js']
            }
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            test: {
                options: {
                    jshintrc: 'test/.jshintrc'
                },
                src: ['test/*.js']
            },
        },
        concurrent: {
            'test-sauce': [], // dynamically filled
        },
        watch: {
            gruntfile: {
                files: '<%= jshint.gruntfile.src %>',
                tasks: ['jshint:gruntfile']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test']
            },
        }
    };

    _.forIn(desireds,function(desired, key) {
        gruntConfig.env[key] = {
            DESIRED: JSON.stringify(desired)
        };
        //gruntConfig.concurrent['test-sauce'].push('test:sauce:' + key);
    });

module.exports = function(grunt) {
	gruntConfig.pkg = grunt.file.readJSON('package.json');

    grunt.initConfig(gruntConfig);

    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-istanbul');
    grunt.loadNpmTasks('grunt-env');
    grunt.loadNpmTasks('grunt-simple-mocha');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('dev-test', ['env:test', 'clean:coverage', 'copy:resourcesForInstrumented', 'instrument', 'mochaTest:server-side-spec']);
    grunt.registerTask('dev-test-cov', ['env:test', 'clean:coverage', 'copy:resourcesForInstrumented', 'instrument', 'mochaTest:server-side', 'storeCoverage', 'makeReport']);
    grunt.registerTask('dev-fvtspec', ['env:test', 'clean:coverage', 'mochaTest:fvt-spec']);
    grunt.registerTask('dev-fvt', ['env:test', 'clean:coverage', 'mochaTest:fvt']);
    grunt.registerTask('test_real', ['env:chrome', 'simplemocha:sauce:' + _(desireds).keys().first()]);
    grunt.registerTask('test_fake', ['env:chrome', 'simplemocha:sauce_node:' + _(desireds).keys().first()]);
};
<|endoftext|>


<commit_before>(function () {
	'use strict';

	var document = typeof window !== 'undefined' && typeof window.document !== 'undefined' ? window.document : {};
	var isCommonjs = typeof module !== 'undefined' && module.exports;

	var fn = (function () {
		var val;

		var fnMap = [
			[
				'requestFullscreen',
				'exitFullscreen',
				'fullscreenElement',
				'fullscreenEnabled',
				'fullscreenchange',
				'fullscreenerror'
			],
			// New WebKit
			[
				'webkitRequestFullscreen',
				'webkitExitFullscreen',
				'webkitFullscreenElement',
				'webkitFullscreenEnabled',
				'webkitfullscreenchange',
				'webkitfullscreenerror'

			],
			// Old WebKit
			[
				'webkitRequestFullScreen',
				'webkitCancelFullScreen',
				'webkitCurrentFullScreenElement',
				'webkitCancelFullScreen',
				'webkitfullscreenchange',
				'webkitfullscreenerror'

			],
			[
				'mozRequestFullScreen',
				'mozCancelFullScreen',
				'mozFullScreenElement',
				'mozFullScreenEnabled',
				'mozfullscreenchange',
				'mozfullscreenerror'
			],
			[
				'msRequestFullscreen',
				'msExitFullscreen',
				'msFullscreenElement',
				'msFullscreenEnabled',
				'MSFullscreenChange',
				'MSFullscreenError'
			]
		];

		var i = 0;
		var l = fnMap.length;
		var ret = {};

		for (; i < l; i++) {
			val = fnMap[i];
			if (val && val[1] in document) {
				for (i = 0; i < val.length; i++) {
					ret[fnMap[0][i]] = val[i];
				}
				return ret;
			}
		}

		return false;
	})();

	var eventNameMap = {
		change: fn.fullscreenchange,
		error: fn.fullscreenerror
	};

	var screenfull = {
		request: function (element) {
			return new Promise(function (resolve, reject) {
				var onFullScreenEntered = function () {
					this.off('change', onFullScreenEntered);
					resolve();
				}.bind(this);

				this.on('change', onFullScreenEntered);

				element = element || document.documentElement;

				Promise.resolve(element[fn.requestFullscreen]()).catch(reject);
			}.bind(this));
		},
		exit: function () {
			return new Promise(function (resolve, reject) {
				if (!this.isFullscreen) {
					resolve();
					return;
				}

				var onFullScreenExit = function () {
					this.off('change', onFullScreenExit);
					resolve();
				}.bind(this);

				this.on('change', onFullScreenExit);

				Promise.resolve(document[fn.exitFullscreen]()).catch(reject);
			}.bind(this));
		},
		toggle: function (element) {
			return this.isFullscreen ? this.exit() : this.request(element);
		},
		onchange: function (callback) {
			this.on('change', callback);
		},
		onerror: function (callback) {
			this.on('error', callback);
		},
		on: function (event, callback) {
			var eventName = eventNameMap[event];
			if (eventName) {
				document.addEventListener(eventName, callback, false);
			}
		},
		off: function (event, callback) {
			var eventName = eventNameMap[event];
			if (eventName) {
				document.removeEventListener(eventName, callback, false);
			}
		},
		raw: fn
	};

	if (!fn) {
		if (isCommonjs) {
			module.exports = {isEnabled: false};
		} else {
			window.screenfull = {isEnabled: false};
		}

		return;
	}

	Object.defineProperties(screenfull, {
		isFullscreen: {
			get: function () {
				return Boolean(document[fn.fullscreenElement]);
			}
		},
		element: {
			enumerable: true,
			get: function () {
				return document[fn.fullscreenElement];
			}
		},
		isEnabled: {
			enumerable: true,
			get: function () {
				// Coerce to boolean in case of old WebKit
				return Boolean(document[fn.fullscreenEnabled]);
			}
		}
	});

	if (isCommonjs) {
		module.exports = screenfull;
	} else {
		window.screenfull = screenfull;
	}
})();
<commit_msg>Return the native promise when it exists (#168)<commit_after>(function () {
	'use strict';

	var document = typeof window !== 'undefined' && typeof window.document !== 'undefined' ? window.document : {};
	var isCommonjs = typeof module !== 'undefined' && module.exports;

	var fn = (function () {
		var val;

		var fnMap = [
			[
				'requestFullscreen',
				'exitFullscreen',
				'fullscreenElement',
				'fullscreenEnabled',
				'fullscreenchange',
				'fullscreenerror'
			],
			// New WebKit
			[
				'webkitRequestFullscreen',
				'webkitExitFullscreen',
				'webkitFullscreenElement',
				'webkitFullscreenEnabled',
				'webkitfullscreenchange',
				'webkitfullscreenerror'

			],
			// Old WebKit
			[
				'webkitRequestFullScreen',
				'webkitCancelFullScreen',
				'webkitCurrentFullScreenElement',
				'webkitCancelFullScreen',
				'webkitfullscreenchange',
				'webkitfullscreenerror'

			],
			[
				'mozRequestFullScreen',
				'mozCancelFullScreen',
				'mozFullScreenElement',
				'mozFullScreenEnabled',
				'mozfullscreenchange',
				'mozfullscreenerror'
			],
			[
				'msRequestFullscreen',
				'msExitFullscreen',
				'msFullscreenElement',
				'msFullscreenEnabled',
				'MSFullscreenChange',
				'MSFullscreenError'
			]
		];

		var i = 0;
		var l = fnMap.length;
		var ret = {};

		for (; i < l; i++) {
			val = fnMap[i];
			if (val && val[1] in document) {
				for (i = 0; i < val.length; i++) {
					ret[fnMap[0][i]] = val[i];
				}
				return ret;
			}
		}

		return false;
	})();

	var eventNameMap = {
		change: fn.fullscreenchange,
		error: fn.fullscreenerror
	};

	var screenfull = {
		request: function (element) {
			return new Promise(function (resolve, reject) {
				var onFullScreenEntered = function () {
					this.off('change', onFullScreenEntered);
					resolve();
				}.bind(this);

				this.on('change', onFullScreenEntered);

				element = element || document.documentElement;

				var returnPromise = element[fn.requestFullscreen]();

				if (returnPromise instanceof Promise) {
					returnPromise.then(onFullScreenEntered).catch(reject);
				}
			}.bind(this));
		},
		exit: function () {
			return new Promise(function (resolve, reject) {
				if (!this.isFullscreen) {
					resolve();
					return;
				}

				var onFullScreenExit = function () {
					this.off('change', onFullScreenExit);
					resolve();
				}.bind(this);

				this.on('change', onFullScreenExit);

				var returnPromise = document[fn.exitFullscreen]();

				if (returnPromise instanceof Promise) {
					returnPromise.then(onFullScreenExit).catch(reject);
				}
			}.bind(this));
		},
		toggle: function (element) {
			return this.isFullscreen ? this.exit() : this.request(element);
		},
		onchange: function (callback) {
			this.on('change', callback);
		},
		onerror: function (callback) {
			this.on('error', callback);
		},
		on: function (event, callback) {
			var eventName = eventNameMap[event];
			if (eventName) {
				document.addEventListener(eventName, callback, false);
			}
		},
		off: function (event, callback) {
			var eventName = eventNameMap[event];
			if (eventName) {
				document.removeEventListener(eventName, callback, false);
			}
		},
		raw: fn
	};

	if (!fn) {
		if (isCommonjs) {
			module.exports = {isEnabled: false};
		} else {
			window.screenfull = {isEnabled: false};
		}

		return;
	}

	Object.defineProperties(screenfull, {
		isFullscreen: {
			get: function () {
				return Boolean(document[fn.fullscreenElement]);
			}
		},
		element: {
			enumerable: true,
			get: function () {
				return document[fn.fullscreenElement];
			}
		},
		isEnabled: {
			enumerable: true,
			get: function () {
				// Coerce to boolean in case of old WebKit
				return Boolean(document[fn.fullscreenEnabled]);
			}
		}
	});

	if (isCommonjs) {
		module.exports = screenfull;
	} else {
		window.screenfull = screenfull;
	}
})();
<|endoftext|>


<commit_before>var angular = require('./lib/angular');

var indexController = require('./lib/controller/index');
var userController = require('./lib/controller/user');
var createUserController = require('./lib/controller/createUser');

var userService = require('./lib/services/user');
var locationService = require('./lib/services/location');
var transactionService = require('./lib/services/transaction');

var settings = require('./lib/settings');

var app = angular.module('strichliste', ['ngRoute', 'ngIdle'])
   .config(function ($routeProvider) {

       $routeProvider
           .when('/', {
               templateUrl: 'partials/index.html',
               controller: 'IndexController'
           })
           .when('/user/:user_id', {
               templateUrl: 'partials/user.html',
               controller: 'UserController'
           })
           .when('/createUser', {
               templateUrl: 'partials/createUser.html',
               controller: 'CreateUserController'
           })
           .otherwise({
               redirectTo: '/'
           });
   });

indexController.install(app);
userController.install(app);
createUserController.install(app);

userService.install(app);
locationService.install(app);
transactionService.install(app);
<commit_msg>removed reference to ngIdle<commit_after>var angular = require('./lib/angular');

var indexController = require('./lib/controller/index');
var userController = require('./lib/controller/user');
var createUserController = require('./lib/controller/createUser');

var userService = require('./lib/services/user');
var locationService = require('./lib/services/location');
var transactionService = require('./lib/services/transaction');

var settings = require('./lib/settings');

var app = angular.module('strichliste', ['ngRoute'])
   .config(function ($routeProvider) {

       $routeProvider
           .when('/', {
               templateUrl: 'partials/index.html',
               controller: 'IndexController'
           })
           .when('/user/:user_id', {
               templateUrl: 'partials/user.html',
               controller: 'UserController'
           })
           .when('/createUser', {
               templateUrl: 'partials/createUser.html',
               controller: 'CreateUserController'
           })
           .otherwise({
               redirectTo: '/'
           });
   });

indexController.install(app);
userController.install(app);
createUserController.install(app);

userService.install(app);
locationService.install(app);
transactionService.install(app);
<|endoftext|>


<commit_before>import LineIterator from './line-iterator'
import {compare, minPoint, traverse, traversalDistance, ZERO_POINT} from './point-helpers'

export default class TokenIterator {
  constructor (screenLineIndex) {
    this.screenLineIndex = screenLineIndex
    this.lineIterator = new LineIterator(screenLineIndex)
  }

  seekToScreenPosition (targetPosition) {
    let clippedTargetPosition = targetPosition
    if (clippedTargetPosition.row < 0) {
      clippedTargetPosition = ZERO_POINT
    }
    if (clippedTargetPosition.column < 0) {
      clippedTargetPosition = {row: clippedTargetPosition.row, column: 0}
    }
    let lastScreenRow = this.screenLineIndex.getLastScreenRow()
    if (clippedTargetPosition.row > lastScreenRow) {
      clippedTargetPosition = {row: lastScreenRow, column: Infinity}
    }

    this.lineIterator.seekToScreenPosition(clippedTargetPosition)

    let tokens = this.lineIterator.getTokens()
    let targetColumn = clippedTargetPosition.column
    let startIndex = 0
    let endIndex = tokens.length
    let token

    while (startIndex < endIndex) {
      this.tokenIndex = Math.floor((startIndex + endIndex) / 2)
      token = tokens[this.tokenIndex]

      if (targetColumn <= token.screenStartOffset) {
        endIndex = this.tokenIndex
      } else {
        if (targetColumn <= token.screenEndOffset) {
          this.tokenIndex = this.tokenIndex
          return true
        } else {
          startIndex = this.tokenIndex + 1
        }
      }
    }
    return false
  }

  seekToBufferPosition (targetPosition) {
    let clippedTargetPosition = targetPosition
    if (clippedTargetPosition.row < 0) {
      clippedTargetPosition = ZERO_POINT
    }
    if (clippedTargetPosition.column < 0) {
      clippedTargetPosition = {row: clippedTargetPosition.row, column: 0}
    }

    this.lineIterator.seekToBufferPosition(clippedTargetPosition)

    clippedTargetPosition = minPoint(clippedTargetPosition, this.lineIterator.getBufferEnd())

    let tokens = this.lineIterator.getTokens()

    let targetOffsetInLine = traversalDistance(clippedTargetPosition, this.lineIterator.getBufferStart())
    let startIndex = 0
    let endIndex = tokens.length

    while (startIndex < endIndex) {
      this.tokenIndex = Math.floor((startIndex + endIndex) / 2)
      let token = tokens[this.tokenIndex]

      if (compare(targetOffsetInLine, token.bufferStartOffset) <= 0) {
        endIndex = this.tokenIndex
      } else {
        if (compare(targetOffsetInLine, token.bufferEndOffset) <= 0) {
          break
        } else {
          startIndex = this.tokenIndex + 1
        }
      }
    }

    while (this.tokenIndex > 0 && compare(targetOffsetInLine, this.getCurrentToken().bufferStartOffset) === 0) {
      this.tokenIndex--
    }
  }

  moveToSuccessor () {
    this.tokenIndex++
    while (this.tokenIndex === this.lineIterator.getTokens().length) {
      if (this.lineIterator.moveToSuccessor()) {
        this.tokenIndex = 0
      } else {
        return false
      }
    }
    return true
  }

  getScreenStart () {
    let row = this.lineIterator.getScreenRow()
    let column = this.getCurrentToken().screenStartOffset
    return {row, column}
  }

  getScreenEnd () {
    let row = this.lineIterator.getScreenRow()
    let column = this.getCurrentToken().screenEndOffset
    return {row, column}
  }

  getBufferStart () {
    let lineStart = this.lineIterator.getBufferStart()
    let tokenStartOffset = this.getCurrentToken().bufferStartOffset
    return traverse(lineStart, tokenStartOffset)
  }

  getBufferEnd () {
    let lineStart = this.lineIterator.getBufferStart()
    let tokenStartOffset = this.getCurrentToken().bufferEndOffset
    return traverse(lineStart, tokenStartOffset)
  }

  getMetadata () {
    return this.getCurrentToken().metadata
  }

  getCurrentToken () {
    return this.lineIterator.getTokens()[this.tokenIndex]
  }
}
<commit_msg>Add position translation methods to TokenIterator<commit_after>import LineIterator from './line-iterator'
import {compare, minPoint, traverse, traversalDistance, ZERO_POINT} from './point-helpers'

export default class TokenIterator {
  constructor (screenLineIndex) {
    this.screenLineIndex = screenLineIndex
    this.lineIterator = new LineIterator(screenLineIndex)
  }

  seekToScreenPosition (targetPosition) {
    let clippedTargetPosition = targetPosition
    if (clippedTargetPosition.row < 0) {
      clippedTargetPosition = ZERO_POINT
    }
    if (clippedTargetPosition.column < 0) {
      clippedTargetPosition = {row: clippedTargetPosition.row, column: 0}
    }
    let lastScreenRow = this.screenLineIndex.getLastScreenRow()
    if (clippedTargetPosition.row > lastScreenRow) {
      clippedTargetPosition = {row: lastScreenRow, column: Infinity}
    }

    this.lineIterator.seekToScreenPosition(clippedTargetPosition)

    let tokens = this.lineIterator.getTokens()
    let targetColumn = clippedTargetPosition.column
    let startIndex = 0
    let endIndex = tokens.length
    let token

    while (startIndex < endIndex) {
      this.tokenIndex = Math.floor((startIndex + endIndex) / 2)
      token = tokens[this.tokenIndex]

      if (targetColumn <= token.screenStartOffset) {
        endIndex = this.tokenIndex
      } else {
        if (targetColumn <= token.screenEndOffset) {
          this.tokenIndex = this.tokenIndex
          return true
        } else {
          startIndex = this.tokenIndex + 1
        }
      }
    }
    return false
  }

  seekToBufferPosition (targetPosition) {
    let clippedTargetPosition = targetPosition
    if (clippedTargetPosition.row < 0) {
      clippedTargetPosition = ZERO_POINT
    }
    if (clippedTargetPosition.column < 0) {
      clippedTargetPosition = {row: clippedTargetPosition.row, column: 0}
    }

    this.lineIterator.seekToBufferPosition(clippedTargetPosition)

    clippedTargetPosition = minPoint(clippedTargetPosition, this.lineIterator.getBufferEnd())

    let tokens = this.lineIterator.getTokens()

    let targetOffsetInLine = traversalDistance(clippedTargetPosition, this.lineIterator.getBufferStart())
    let startIndex = 0
    let endIndex = tokens.length

    while (startIndex < endIndex) {
      this.tokenIndex = Math.floor((startIndex + endIndex) / 2)
      let token = tokens[this.tokenIndex]

      if (compare(targetOffsetInLine, token.bufferStartOffset) <= 0) {
        endIndex = this.tokenIndex
      } else {
        if (compare(targetOffsetInLine, token.bufferEndOffset) <= 0) {
          break
        } else {
          startIndex = this.tokenIndex + 1
        }
      }
    }

    while (this.tokenIndex > 0 && compare(targetOffsetInLine, this.getCurrentToken().bufferStartOffset) === 0) {
      this.tokenIndex--
    }
  }

  moveToSuccessor () {
    this.tokenIndex++
    while (this.tokenIndex === this.lineIterator.getTokens().length) {
      if (this.lineIterator.moveToSuccessor()) {
        this.tokenIndex = 0
      } else {
        return false
      }
    }
    return true
  }

  getScreenStart () {
    let row = this.lineIterator.getScreenRow()
    let column = this.getCurrentToken().screenStartOffset
    return {row, column}
  }

  getScreenEnd () {
    let row = this.lineIterator.getScreenRow()
    let column = this.getCurrentToken().screenEndOffset
    return {row, column}
  }

  getBufferStart () {
    let lineStart = this.lineIterator.getBufferStart()
    let tokenStartOffset = this.getCurrentToken().bufferStartOffset
    return traverse(lineStart, tokenStartOffset)
  }

  getBufferEnd () {
    let lineStart = this.lineIterator.getBufferStart()
    let tokenStartOffset = this.getCurrentToken().bufferEndOffset
    return traverse(lineStart, tokenStartOffset)
  }

  getMetadata () {
    return this.getCurrentToken().metadata
  }

  translateBufferPosition (bufferPosition) {
    if (compare(bufferPosition, this.getBufferStart()) < 0) {
      throw new Error(`Position ${formatPoint(bufferPosition)} is less than the current token's start (${formatPoint(this.getBufferStart())})`)
    }

    return traverse(this.getScreenStart(), traversalDistance(bufferPosition, this.getBufferStart()))
  }

  translateScreenPosition (screenPosition) {
    if (compare(screenPosition, this.getScreenStart()) < 0) {
      throw new Error(`Position ${formatPoint(screenPosition)} is less than the current token's start (${formatPoint(this.getScreenStart())})`)
    }

    return traverse(this.getBufferStart(), traversalDistance(screenPosition, this.getScreenStart()))
  }

  getCurrentToken () {
    return this.lineIterator.getTokens()[this.tokenIndex]
  }
}
<|endoftext|>


<commit_before>// api.js router setup
var express = require('express');
var router = express.Router();

var fs = require('fs');
var path = require('path');

// included functions
var generateSchedules = require('./lib/generateSchedules');
var generateSchedulesFirebase = require('./lib/generateScheduleFirebase');
var TROJAN = require('trojan-course-api');
var _ = require('lodash');

// firebase
var db = require('./lib/firebase');
var refSched = db.ref('/20171');
var refCourse = db.ref('/courses');

var suffix = '@usc.edu';

// ROUTES OF API

// middleware
router.use(function (req, res, next) {
  // console.log('api call made');
  next();
});

router.route('/')
  .get(function (req, res) {
    res.json({
      messages: "here are some methods you can call",
      rest_api: ['schedule', 'trojan', 'refreshDatabase']
    });
  });

router.route('/refreshDatabase')
  .get(function (req, res) {

    // get full list of departments with courses
    TROJAN.deptsCN().then(function (dlist) {
      var arrayOfDepts = Object.keys(dlist);

      // we want to iterate through each dept and grab its data,
      // and return the final results once we process the last dept.
      var maxIndex = arrayOfDepts.length;
      var index = 0;

      // this is where the data will be stored.
      var masterCourses = {};

      // now, go through all departments
      TROJAN.deptBatch_cb(arrayOfDepts, null, function (deptData) {
        var courses = deptData.courses;

        // merge it with the master data collector
        masterCourses = _.merge(masterCourses, courses);
        console.log(courses);
        refCourse.update(courses);
        index += 1;

        // once we hit the last index, turn the desc into the key.
        if (maxIndex <= index) {
          res.json(masterCourses);
        }
      });
    });
  });

router.route('/schedule')
  .get(function (req, res) {
    // for testing purposes only
    var courses = req.query.courses;
    var anchors = req.query.anchors;
    var blocks = req.query.blocks;
    if (courses && courses.length > 0) {
      if (!_.isArray(courses)) courses = courses.split(',');
      // taking array of courses, generate schedule
      generateSchedulesFirebase(courses, anchors, blocks, function (data) {
        // sort results by score
        data.results.sort(function (a, b) {
          if (a.score < b.score) return -1;
          else if (a.score > b.score) return 1;
          else return 0;
        });

        // respond json
        res.json(data);
      });
    } else {
      res.json({
        error: 'no courses defined'
      });
    }
  });

router.route('/update_server').post(function (req, res) {
  var courses = req.query.courses || [];
  // due diligence
  var uniqCourses = _.uniq(courses.map(function (courseId) { return courseId.split('-')[0]; }));
  for (var id of uniqCourses) {
    TROJAN.courses(id).then(function (courseData) {
      if (courseData) {
        refCourse.update(courseData);
      }
    });
  }
  res.json({ message: 'success', courses });
});

router.route('/schedule/:user_email')
  .post(function (req, res) {
    var userEmail = req.params.user_email.toLowerCase();
    if (validateEmail(userEmail)) {
      userEmail = userEmail.split('@')[0];
      refSched.orderByKey().equalTo(userEmail)
        .once('value')
        .then(function(snap) {

          if (!snap.exists()) {
            refSched.child(userEmail).set({
              ts: Date.now(),
              email: userEmail + suffix,
              courses: [],
              anchors: {},
              blocks: []
            });
            res.json({
              message: 'new user created',
              user_email: userEmail + suffix,
              courses: [],
              anchors: {},
              blocks: []
            });
          } else {
            var courses = snap.val()[userEmail].courses || [];
            var anchors = snap.val()[userEmail].anchors || {};
            var blocks = snap.val()[userEmail].blocks || [];
            res.json({
              message: 'user exists',
              user_email: userEmail + suffix,
              courses: courses,
              anchors: anchors,
              blocks: blocks,
            });
          }
        }).catch(function (e) {
          return res.status(400).json({ error: e.message });
        });
    } else {
      res.json({
        error: 'not a valid email'
      });
    }
  })
  .put(function (req, res) {
    var userEmail = req.params.user_email.toLowerCase();
    if (validateEmail(userEmail)) {
      userEmail = userEmail.split('@')[0];
      refSched.orderByKey().equalTo(userEmail).once('value')
        .then(function(snap) {
          if (!snap.exists()) {
            res.json({
              error: 'cannot mutate, email does not exist',
              user_email: userEmail + suffix
            });
          } else {
            let courses = req.body.courses || [];
            let anchors = req.body.anchors || {};
            let blocks = req.body.blocks || [];

            refSched.child(userEmail).update({
              courses,
              anchors,
              blocks
            });

            res.json({
              message: 'user data updated',
              user_email: userEmail + suffix,
              courses: courses,
              anchors: anchors,
              blocks: blocks
            });
          }
        }).catch(function (e) {
          return res.status(400).json({ error: e.message });
        });
    } else {
      res.json({
        error: 'not a valid email'
      });
    }
  })
  .get(function (req, res) {
    var userEmail = req.params.user_email.toLowerCase();
    console.log(userEmail);
    if (validateEmail(userEmail)) {
      userEmail = userEmail.split('@')[0];
      refSched.orderByKey().equalTo(userEmail).once('value', function(snap) {
        if (!snap.exists()) {
          res.json({
            error: 'cannot mutate, email does not exist',
            user_email: userEmail + suffix
          });
        } else {
          var courses = snap.val()[userEmail].courses || [];
          var anchors = snap.val()[userEmail].anchors || {};
          var blocks = snap.val()[userEmail].blocks || [];

          res.json({
            message: 'user data retrieved',
            user_email: userEmail + suffix,
            courses: courses,
            anchors: anchors,
            blocks: blocks
          });
        }
      });
    } else {
      res.json({
        error: 'not a valid email'
      });
    }
  });

router.route('/verify/:course_id')
  .get(function (req, res) {
    refCourse.child(req.params.course_id).once('value', function(snap) {
      res.json({ exists: snap.exists() });
      TROJAN.courses(req.params.course_id.split('-')[0])
        .then(function (courseData) {
        if (courseData) {
          refCourse.update(courseData);
        }
      });
    });
  });

router.route('/autocomplete')
  .get(function(req, res) {
    res.json([]);
  });
router.route('/autocomplete/:text')
  .get(function (req, res) {
    var text = req.params.text;
    text = text.toUpperCase();
    refCourse
      .orderByKey()
      .startAt(text)
      .limitToFirst(8)
      // .startAt(text).endAt(text + '\uf8ff')
      // .limit(5)
      // res.json({hello:text})
      .once('value')
      .then(function (snap) {
        res.json(_.values(_.mapValues(snap.val(), function (coursedata, key) {
          return {
            courseId: key,
            title: coursedata.title
          }
        })));
      }).catch(function (e) {
        return res.status(400).json({ error: e.message });
      });
  });

router.route('/upload/:user_email')
  .post(function (req, res) {

    var userEmail = req.params.user_email.toLowerCase();

    if (validateEmail(userEmail) && 'data' in req.body) {
      userEmail = userEmail.split('@')[0];

      var data = req.body.data.replace(/^data:image\/\w+;base64,/, "");
      var dest = '../../www/screenshots/';
      var buf = new Buffer(data, 'base64');

      refSched.orderByKey().equalTo(userEmail).once('value', function(snap) {

        if (!snap.exists()) {
          res.json({ error: 'not a valid email' });
        } else {
          var destination = path.join(__dirname, 'screenshots/' + snap.key + '.jpg')
          fs.writeFile(destination, buf, (err) => {
            if (err) {
              res.json({
                error: 'unable to upload file',
                why: err
              });
            } else {
              res.json({
                message: 'file uploaded',
                user_email: userEmail + suffix,
                url: 'screenshots/' + snap.key + '.jpg'
              });
            }
          });
        }
      });
    } else {
      res.json({ error: 'not a valid email or file' });
    }

  });

router.route('/trojan')
  .get(function (req, res) {
    res.json({
      trojan: ['terms', 'current_term', 'depts', 'dept', 'courses', 'dept_info', 'course', 'section', 'depts_flat', 'deptsY', 'deptsC', 'deptsN', 'deptsCN', 'deptBatch']
    });
  });

router.route('/trojan/:action')
  .get(function (req, res) {
    var action = req.params.action;
    var q = req.query;

    switch (action) {
      case 'terms':
        TROJAN.terms().then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'current_term':
        TROJAN.current_term().then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'depts':
        if (q.term) TROJAN.depts(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        else res.json({ depts: ['term'] })
        break;
      case 'dept':
        TROJAN.dept(q.dept, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'courses':
        TROJAN.courses(q.dept, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'dept_info':
        TROJAN.dept_info(q.dept, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'course':
        TROJAN.course(q.dept, q.num, q.seq, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'section':
        TROJAN.section(q.dept, q.num, q.seq, q.sect, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'depts_flat':
        TROJAN.depts_flat(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsY':
        TROJAN.deptsY(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsC':
        TROJAN.deptsC(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsN':
        TROJAN.deptsN(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsCN':
        TROJAN.deptsCN(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptBatch':
        TROJAN.deptBatch(q.depts).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      default:
        res.json({ error: 'action not found' });
    }
  });

router.route('/usercount')
  .get(function (req, res) {
    refSched.once("value", function(snapshot) {
      res.json({
        userCount: snapshot.numChildren()
      });
    });
  });

module.exports = router;

function validateEmail(email) {
  var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(email) && email.indexOf('@usc.edu') > 1;
}
<commit_msg>fb quirk<commit_after>// api.js router setup
var express = require('express');
var router = express.Router();

var fs = require('fs');
var path = require('path');

// included functions
var generateSchedules = require('./lib/generateSchedules');
var generateSchedulesFirebase = require('./lib/generateScheduleFirebase');
var TROJAN = require('trojan-course-api');
var _ = require('lodash');

// firebase
var db = require('./lib/firebase');
var refSched = db.ref('/20171');
var refCourse = db.ref('/courses');

var suffix = '@usc.edu';

// ROUTES OF API

// middleware
router.use(function (req, res, next) {
  // console.log('api call made');
  next();
});

router.route('/')
  .get(function (req, res) {
    res.json({
      messages: "here are some methods you can call",
      rest_api: ['schedule', 'trojan', 'refreshDatabase']
    });
  });

router.route('/refreshDatabase')
  .get(function (req, res) {

    // get full list of departments with courses
    TROJAN.deptsCN().then(function (dlist) {
      var arrayOfDepts = Object.keys(dlist);

      // we want to iterate through each dept and grab its data,
      // and return the final results once we process the last dept.
      var maxIndex = arrayOfDepts.length;
      var index = 0;

      // this is where the data will be stored.
      var masterCourses = {};

      // now, go through all departments
      TROJAN.deptBatch_cb(arrayOfDepts, null, function (deptData) {
        var courses = deptData.courses;

        // merge it with the master data collector
        masterCourses = _.merge(masterCourses, courses);
        console.log(courses);
        refCourse.update(courses);
        index += 1;

        // once we hit the last index, turn the desc into the key.
        if (maxIndex <= index) {
          res.json(masterCourses);
        }
      });
    });
  });

router.route('/schedule')
  .get(function (req, res) {
    // for testing purposes only
    var courses = req.query.courses;
    var anchors = req.query.anchors;
    var blocks = req.query.blocks;
    if (courses && courses.length > 0) {
      if (!_.isArray(courses)) courses = courses.split(',');
      // taking array of courses, generate schedule
      generateSchedulesFirebase(courses, anchors, blocks, function (data) {
        // sort results by score
        data.results.sort(function (a, b) {
          if (a.score < b.score) return -1;
          else if (a.score > b.score) return 1;
          else return 0;
        });

        // respond json
        res.json(data);
      });
    } else {
      res.json({
        error: 'no courses defined'
      });
    }
  });

router.route('/update_server').post(function (req, res) {
  var courses = req.query.courses || [];
  // due diligence
  var uniqCourses = _.uniq(courses.map(function (courseId) { return courseId.split('-')[0]; }));
  for (var id of uniqCourses) {
    TROJAN.courses(id).then(function (courseData) {
      if (courseData) {
        refCourse.update(courseData);
      }
    });
  }
  res.json({ message: 'success', courses });
});

router.route('/schedule/:user_email')
  .post(function (req, res) {
    var userEmail = req.params.user_email.toLowerCase();
    if (validateEmail(userEmail)) {
      userEmail = userEmail.split('@')[0].replace('.', '-');
      refSched.orderByKey().equalTo(userEmail)
        .once('value')
        .then(function(snap) {

          if (!snap.exists()) {
            refSched.child(userEmail).set({
              ts: Date.now(),
              email: req.params.user_email.toLowerCase(),
              courses: [],
              anchors: {},
              blocks: []
            });
            res.json({
              message: 'new user created',
              user_email: req.params.user_email.toLowerCase(),
              courses: [],
              anchors: {},
              blocks: []
            });
          } else {
            var courses = snap.val()[userEmail].courses || [];
            var anchors = snap.val()[userEmail].anchors || {};
            var blocks = snap.val()[userEmail].blocks || [];
            res.json({
              message: 'user exists',
              user_email: req.params.user_email.toLowerCase(),
              courses: courses,
              anchors: anchors,
              blocks: blocks,
            });
          }
        }).catch(function (e) {
          return res.status(400).json({ error: e.message });
        });
    } else {
      res.json({
        error: 'not a valid email'
      });
    }
  })
  .put(function (req, res) {
    var userEmail = req.params.user_email.toLowerCase();
    if (validateEmail(userEmail)) {
      userEmail = userEmail.split('@')[0].replace('.', '-');
      refSched.orderByKey().equalTo(userEmail).once('value')
        .then(function(snap) {
          if (!snap.exists()) {
            res.json({
              error: 'cannot mutate, email does not exist',
              user_email: req.params.user_email.toLowerCase()
            });
          } else {
            let courses = req.body.courses || [];
            let anchors = req.body.anchors || {};
            let blocks = req.body.blocks || [];

            refSched.child(userEmail).update({
              courses,
              anchors,
              blocks
            });

            res.json({
              message: 'user data updated',
              user_email: req.params.user_email.toLowerCase(),
              courses: courses,
              anchors: anchors,
              blocks: blocks
            });
          }
        }).catch(function (e) {
          return res.status(400).json({ error: e.message });
        });
    } else {
      res.json({
        error: 'not a valid email'
      });
    }
  })
  .get(function (req, res) {
    var userEmail = req.params.user_email.toLowerCase();
    console.log(userEmail);
    if (validateEmail(userEmail)) {
      userEmail = userEmail.split('@')[0].replace('.', '-');
      refSched.orderByKey().equalTo(userEmail).once('value', function(snap) {
        if (!snap.exists()) {
          res.json({
            error: 'cannot mutate, email does not exist',
            user_email: req.params.user_email.toLowerCase()
          });
        } else {
          var courses = snap.val()[userEmail].courses || [];
          var anchors = snap.val()[userEmail].anchors || {};
          var blocks = snap.val()[userEmail].blocks || [];

          res.json({
            message: 'user data retrieved',
            user_email: req.params.user_email.toLowerCase(),
            courses: courses,
            anchors: anchors,
            blocks: blocks
          });
        }
      });
    } else {
      res.json({
        error: 'not a valid email'
      });
    }
  });

router.route('/verify/:course_id')
  .get(function (req, res) {
    refCourse.child(req.params.course_id).once('value', function(snap) {
      res.json({ exists: snap.exists() });
      TROJAN.courses(req.params.course_id.split('-')[0])
        .then(function (courseData) {
        if (courseData) {
          refCourse.update(courseData);
        }
      });
    });
  });

router.route('/autocomplete')
  .get(function(req, res) {
    res.json([]);
  });
router.route('/autocomplete/:text')
  .get(function (req, res) {
    var text = req.params.text;
    text = text.toUpperCase();
    refCourse
      .orderByKey()
      .startAt(text)
      .limitToFirst(8)
      // .startAt(text).endAt(text + '\uf8ff')
      // .limit(5)
      // res.json({hello:text})
      .once('value')
      .then(function (snap) {
        res.json(_.values(_.mapValues(snap.val(), function (coursedata, key) {
          return {
            courseId: key,
            title: coursedata.title
          }
        })));
      }).catch(function (e) {
        return res.status(400).json({ error: e.message });
      });
  });

router.route('/upload/:user_email')
  .post(function (req, res) {

    var userEmail = req.params.user_email.toLowerCase();

    if (validateEmail(userEmail) && 'data' in req.body) {
      userEmail = userEmail.split('@')[0].replace('.', '-');

      var data = req.body.data.replace(/^data:image\/\w+;base64,/, "");
      var dest = '../../www/screenshots/';
      var buf = new Buffer(data, 'base64');

      refSched.orderByKey().equalTo(userEmail).once('value', function(snap) {

        if (!snap.exists()) {
          res.json({ error: 'not a valid email' });
        } else {
          var destination = path.join(__dirname, 'screenshots/' + snap.key + '.jpg')
          fs.writeFile(destination, buf, (err) => {
            if (err) {
              res.json({
                error: 'unable to upload file',
                why: err
              });
            } else {
              res.json({
                message: 'file uploaded',
                user_email: req.params.user_email.toLowerCase(),
                url: 'screenshots/' + snap.key + '.jpg'
              });
            }
          });
        }
      });
    } else {
      res.json({ error: 'not a valid email or file' });
    }

  });

router.route('/trojan')
  .get(function (req, res) {
    res.json({
      trojan: ['terms', 'current_term', 'depts', 'dept', 'courses', 'dept_info', 'course', 'section', 'depts_flat', 'deptsY', 'deptsC', 'deptsN', 'deptsCN', 'deptBatch']
    });
  });

router.route('/trojan/:action')
  .get(function (req, res) {
    var action = req.params.action;
    var q = req.query;

    switch (action) {
      case 'terms':
        TROJAN.terms().then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'current_term':
        TROJAN.current_term().then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'depts':
        if (q.term) TROJAN.depts(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        else res.json({ depts: ['term'] })
        break;
      case 'dept':
        TROJAN.dept(q.dept, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'courses':
        TROJAN.courses(q.dept, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'dept_info':
        TROJAN.dept_info(q.dept, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'course':
        TROJAN.course(q.dept, q.num, q.seq, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'section':
        TROJAN.section(q.dept, q.num, q.seq, q.sect, q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'depts_flat':
        TROJAN.depts_flat(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsY':
        TROJAN.deptsY(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsC':
        TROJAN.deptsC(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsN':
        TROJAN.deptsN(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptsCN':
        TROJAN.deptsCN(q.term).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      case 'deptBatch':
        TROJAN.deptBatch(q.depts).then(res.json).catch(function (e) { return res.status(400).json({ error: e.message }) });
        break;
      default:
        res.json({ error: 'action not found' });
    }
  });

router.route('/usercount')
  .get(function (req, res) {
    refSched.once("value", function(snapshot) {
      res.json({
        userCount: snapshot.numChildren()
      });
    });
  });

module.exports = router;

function validateEmail(email) {
  var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(email) && email.indexOf('@usc.edu') > 1;
}
<|endoftext|>


<commit_before>var mongodb = require('mongodb'),
   express = require('express'),
   flash = require('connect-flash'),
   crypto = require('crypto'),
   fs = require('fs'),
   https = require('https'),
   ObjectID = require('mongodb').ObjectID,
   app = express(),
   passport = require('passport'),
   db,
   itemTypes = ['mailitem', 'fileitem'],
   LocalStrategy = require('passport-local').Strategy,
   passwordHash = require('password-hash');

app.configure(function() {
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.session({ secret: '0k123p,123;!"%;d)_(i123913' }));
  app.use(flash());
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
});

if('development' == app.get('env')) {
  console.log("Enabling development mode");
  app.use(express.errorHandler());
}

passport.serializeUser(function(user, done) {
  done(null, user._id);
});

passport.deserializeUser(function(id, done) {
  var collection = db.collection('user');

  var user = collection.findOne({_id:  new ObjectID(id)}, {username: 1}, function(err, user) {
    if(err) {
      return done(err);
    } else {
      done(err, user);
    }
  });
});

passport.use(new LocalStrategy(
  function(username, password, done) {
    var collection = db.collection('user');

    var user = collection.findOne({username: username}, function(err, user) {
      if(err) {
        return done(err);
      } else {
        if(!user) {
          return done(null, false);
        } else {
          if(!passwordHash.verify(password, user.hash)) {
            return done(null, false);
          } else {
            console.log("Authenticated correctly");
            return done(null, user);
          }
        }
      }
    });
  }
));

app.get('/api/service', ensureAuthenticated, function(req, res) {

  res.write('[');

  var collection = db.collection('service');
  var cursor = collection.find({}, {});
  var first = true;

  cursor.each(function(err,doc) {
    if(doc == null) {
      res.write(']');
      res.end();
    } else {

      if(! first) {
        res.write(',');
      }

      first = false;

      res.write(JSON.stringify(doc));
    }
  });

});

app.get('/api/servicelist/:input', ensureAuthenticated, function(req, res) {

  res.write('[');

  var collection = db.collection('service');
  var cursor = collection.find({name: new RegExp(req.params.input) }, {name: 1, description: 1, version: 1});
  var first = true;

  cursor.each(function(err,doc) {
    if(doc == null) {
      res.write(']');
      res.end();
    } else {

      if(! first) {
        res.write(',');
      }

      first = false;

      res.write('{"name": "' + doc['name'] + '/' + doc['version'] + '", "description": "' + doc['description'] + '"}');
    }
  });

});

app.get('/api/service/:servicename/:serviceversion', ensureAuthenticated, function(req, res) {

  console.log('Obtaining details for service: \"' + req.params.servicename + "/" + req.params.serviceversion + '\"');

  var collection = db.collection('service');
  var doc = collection.findOne({name: req.params.servicename, version: req.params.serviceversion}, function(err, doc) {
    if(doc) {
      res.write(JSON.stringify(doc));
    }
    res.end();

  });

});

app.post('/api/service/:servicename/:serviceversion', ensureAuthenticated, function(req, res) {

  var collection = db.collection('service');

  collection.update({name: req.params.servicename, version: req.params.serviceversion}, {$set: {description: req.body.description, interfaces: req.body.interfaces, dependencies: req.body.dependencies}}, {upsert: true}, function(err, records) {
    res.send(200, { ok: 'Service saved'} );
    console.log('Saving details for service: \"' + req.params.servicename + "/" + req.params.serviceversion + '\"');
  });
});

app.delete('/api/service/:servicename/:serviceversion', ensureAuthenticated, function(req, res) {

  var collection = db.collection('service');

  collection.remove({name: req.params.servicename, version: req.params.serviceversion}, function(err, records) {
    res.send(200, { ok: 'Service deleted'} );
    console.log('Deleting service: \"' + req.params.servicename + "/" + req.params.serviceversion + '\"');
  });
});

app.get('/api/package', ensureAuthenticated, function(req, res) {

  res.write('[');

  var collection = db.collection('package');
  var cursor = collection.find({}, {});
  var first = true;

  cursor.each(function(err,doc) {
    if(doc == null) {
      res.write(']');
      res.end();
    } else {

      if(! first) {
        res.write(',');
      }

      first = false;

      res.write(JSON.stringify(doc));
    }
  });

});

app.get('/api/package/:packagename', ensureAuthenticated, function(req, res) {

  console.log('Obtaining details for package: \"' + req.params.packagename + '\"');

  var collection = db.collection('package');
  var doc = collection.findOne({name: req.params.packagename}, function(err, doc) {
    if(doc) {
      res.write(JSON.stringify(doc));
    }
    res.end();

  });

});

app.post('/api/package/:packagename', ensureAuthenticated, function(req, res) {

  var collection = db.collection('package');

  collection.update({name: req.params.packagename}, {$set: {services: req.body.services}}, {upsert: true}, function(err, records) {
    res.send(200, { ok: 'Package saved'} );
    console.log('Saving details for package: \"' + req.params.packagename + '\"');
  });
});

app.delete('/api/package/:packagename', ensureAuthenticated, function(req, res) {

  var collection = db.collection('package');

  collection.remove({name: req.params.packagename}, function(err, records) {
    res.send(200, { ok: 'Package deleted'} );
    console.log('Deleting package: \"' + req.params.packagename + '\"');
  });
});

app.post('/api/login', passport.authenticate('local'), function(req, res) {
  res.send(req.user);
});

// Authentication

var auth = function(req, res, next) {
  if (!req.isAuthenticated()) {
    res.send(401)
  } else {
    next();
  }
};

app.get('/api/loggedin', function(req, res) {
  res.send(req.isAuthenticated() ? req.user : '0');
});

app.post('/api/logout', function(req, res){
  req.logOut(); res.send(200);
});

// Initialization and execution

mongodb.connect('mongodb://127.0.0.1:27017/fw', function(err, dbhandle) {

  if(err) {
    throw err;
  }

  db = dbhandle;

  var LISTENER_PORT = 9443;
  var CERT_FILE = 'ssl-cert-snakeoil.pem';
  var KEY_FILE = 'ssl-cert-snakeoil.key';
  var DOCUMENT_ROOT = '/var/www/fw.pentestic.com/htdocs/'

  var options = {
    key: fs.readFileSync(KEY_FILE),
    cert: fs.readFileSync(CERT_FILE)
  }

  app.use('/static', express.static(DOCUMENT_ROOT));

  https.createServer(options, app).listen(LISTENER_PORT);
  console.log("FW server started on port " + LISTENER_PORT);
});

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }

  res.redirect('/login')
}
<commit_msg>Modified<commit_after>var mongodb = require('mongodb'),
   express = require('express'),
   flash = require('connect-flash'),
   crypto = require('crypto'),
   fs = require('fs'),
   https = require('https'),
   ObjectID = require('mongodb').ObjectID,
   app = express(),
   passport = require('passport'),
   db,
   itemTypes = ['mailitem', 'fileitem'],
   LocalStrategy = require('passport-local').Strategy,
   passwordHash = require('password-hash');

app.configure(function() {
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.session({ secret: '0k123p,123;!"%;d)_(i123913' }));
  app.use(flash());
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
});

if('development' == app.get('env')) {
  console.log("Enabling development mode");
  app.use(express.errorHandler());
}

passport.serializeUser(function(user, done) {
  done(null, user._id);
});

passport.deserializeUser(function(id, done) {
  var collection = db.collection('user');

  var user = collection.findOne({_id:  new ObjectID(id)}, {username: 1}, function(err, user) {
    if(err) {
      return done(err);
    } else {
      done(err, user);
    }
  });
});

passport.use(new LocalStrategy(
  function(username, password, done) {
    var collection = db.collection('user');

    var user = collection.findOne({username: username}, function(err, user) {
      if(err) {
        return done(err);
      } else {
        if(!user) {
          return done(null, false);
        } else {
          if(!passwordHash.verify(password, user.hash)) {
            return done(null, false);
          } else {
            console.log("Authenticated correctly");
            return done(null, user);
          }
        }
      }
    });
  }
));

app.get('/api/service', ensureAuthenticated, function(req, res) {

  res.write('[');

  var collection = db.collection('service');
  var cursor = collection.find({}, {});
  var first = true;

  cursor.each(function(err,doc) {
    if(doc == null) {
      res.write(']');
      res.end();
    } else {

      if(! first) {
        res.write(',');
      }

      first = false;

      res.write(JSON.stringify(doc));
    }
  });

});

app.get('/api/servicelist/:input', ensureAuthenticated, function(req, res) {

  res.write('[');

  var collection = db.collection('service');
  var cursor = collection.find({name: new RegExp(req.params.input) }, {name: 1, description: 1, version: 1});
  var first = true;

  cursor.each(function(err,doc) {
    if(doc == null) {
      res.write(']');
      res.end();
    } else {

      if(! first) {
        res.write(',');
      }

      first = false;

      res.write('{"name": "' + doc['name'] + '/' + doc['version'] + '", "description": "' + doc['description'] + '"}');
    }
  });

});

app.get('/api/service/:servicename/:serviceversion', ensureAuthenticated, function(req, res) {

  console.log('Obtaining details for service: \"' + req.params.servicename + "/" + req.params.serviceversion + '\"');

  var collection = db.collection('service');
  var doc = collection.findOne({name: req.params.servicename, version: req.params.serviceversion}, function(err, doc) {
    if(doc) {
      res.write(JSON.stringify(doc));
    }
    res.end();

  });

});

app.post('/api/service/:servicename/:serviceversion', ensureAuthenticated, function(req, res) {

  var collection = db.collection('service');

  collection.update({name: req.params.servicename, version: req.params.serviceversion}, {$set: {description: req.body.description, interfaces: req.body.interfaces, dependencies: req.body.dependencies}}, {upsert: true}, function(err, records) {
    res.send(200, { ok: 'Service saved'} );
    console.log('Saving details for service: \"' + req.params.servicename + "/" + req.params.serviceversion + '\"');
  });
});

app.delete('/api/service/:servicename/:serviceversion', ensureAuthenticated, function(req, res) {

  var collection = db.collection('service');

  collection.remove({name: req.params.servicename, version: req.params.serviceversion}, function(err, records) {
    res.send(200, { ok: 'Service deleted'} );
    console.log('Deleting service: \"' + req.params.servicename + "/" + req.params.serviceversion + '\"');
  });
});

app.get('/api/package', ensureAuthenticated, function(req, res) {

  res.write('[');

  var collection = db.collection('package');
  var cursor = collection.find({}, {});
  var first = true;

  cursor.each(function(err,doc) {
    if(doc == null) {
      res.write(']');
      res.end();
    } else {

      if(! first) {
        res.write(',');
      }

      first = false;

      res.write(JSON.stringify(doc));
    }
  });

});

app.get('/api/package/:packagename', ensureAuthenticated, function(req, res) {

  console.log('Obtaining details for package: \"' + req.params.packagename + '\"');

  var collection = db.collection('package');
  var doc = collection.findOne({name: req.params.packagename}, function(err, doc) {
    if(doc) {
      res.write(JSON.stringify(doc));
    }
    res.end();

  });

});

app.post('/api/package/:packagename', ensureAuthenticated, function(req, res) {

  var collection = db.collection('package');

  collection.update({name: req.params.packagename}, {$set: {services: req.body.services}}, {upsert: true}, function(err, records) {
    res.send(200, { ok: 'Package saved'} );
    console.log('Saving details for package: \"' + req.params.packagename + '\"');
  });
});

app.delete('/api/package/:packagename', ensureAuthenticated, function(req, res) {

  var collection = db.collection('package');

  collection.remove({name: req.params.packagename}, function(err, records) {
    res.send(200, { ok: 'Package deleted'} );
    console.log('Deleting package: \"' + req.params.packagename + '\"');
  });
});

app.post('/api/login', passport.authenticate('local'), function(req, res) {
  res.send(req.user);
});

// Authentication

var auth = function(req, res, next) {
  if (!req.isAuthenticated()) {
    res.send(401)
  } else {
    next();
  }
};

app.get('/api/loggedin', function(req, res) {
  res.send(req.isAuthenticated() ? req.user : '0');
});

app.post('/api/logout', function(req, res){
  req.logOut(); res.send(200);
});

// Initialization and execution

mongodb.connect('mongodb://127.0.0.1:27017/fw', function(err, dbhandle) {

  if(err) {
    throw err;
  }

  db = dbhandle;

  var LISTENER_PORT = 9443;
  var CERT_FILE = 'ssl-cert-snakeoil.pem';
  var KEY_FILE = 'ssl-cert-snakeoil.key';
  var DOCUMENT_ROOT = '.'

  var options = {
    key: fs.readFileSync(KEY_FILE),
    cert: fs.readFileSync(CERT_FILE)
  }

  app.use('/static', express.static(DOCUMENT_ROOT));

  https.createServer(options, app).listen(LISTENER_PORT);
  console.log("FW server started on port " + LISTENER_PORT);
});

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }

  res.redirect('/login')
}
<|endoftext|>


<commit_before>/* exported SidebarRow */
// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
//
// Copyright (C) 2014-2017  Daiki Ueno <dueno@src.gnome.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

const { Gc, GObject, Gtk } = imports.gi;

var SidebarRow = GObject.registerClass({
    Properties: {
        'title': GObject.ParamSpec.string(
            'title',
            'Category title', 'Category title',
            GObject.ParamFlags.READWRITE,
            '',
        ),
        'category': GObject.ParamSpec.enum(
            'category',
            'Category', 'Category',
            GObject.ParamFlags.READWRITE,
            Gc.Category.$gtype,
            Gc.Category.NONE,
        ),
        'icon-name': GObject.ParamSpec.string(
            'icon-name',
            'Category Icon Name', 'Category Icon Name',
            GObject.ParamFlags.READWRITE,
            '',
        ),
    },
}, class SidebarRow extends Gtk.ListBoxRow {
    _init() {
        super._init({
            accessible_role: Gtk.AccessibleRole.ROW,
        });
        this._scripts = [];

        let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL });

        let image = new Gtk.Image({ margin_end: 10 });
        this.bind_property('icon-name', image, 'icon-name',
            GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE,
        );
        image.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR);
        hbox.append(image);

        let label = new Gtk.Label({ halign: Gtk.Align.START });
        this.bind_property('title', label, 'label',
            GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE,
        );
        // Because bind_property doesn't work with transform functions
        // TODO: is this really needed?
        this.connect('notify::title', row => {
            row.tooltip_text = _('%s Sidebar Row').format(row.title);
        });
        hbox.append(label);

        this.set_child(hbox);
    }

    get title() {
        return this._title || '';
    }

    set title(title) {
        this._title = title;
    }

    get category() {
        return this._category || Gc.Category.NONE;
    }

    set category(value) {
        this._category = value;
    }
});

<commit_msg>sidebar: cleanup rows spacing<commit_after>/* exported SidebarRow */
// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
//
// Copyright (C) 2014-2017  Daiki Ueno <dueno@src.gnome.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

const { Gc, GObject, Gtk } = imports.gi;

var SidebarRow = GObject.registerClass({
    Properties: {
        'title': GObject.ParamSpec.string(
            'title',
            'Category title', 'Category title',
            GObject.ParamFlags.READWRITE,
            '',
        ),
        'category': GObject.ParamSpec.enum(
            'category',
            'Category', 'Category',
            GObject.ParamFlags.READWRITE,
            Gc.Category.$gtype,
            Gc.Category.NONE,
        ),
        'icon-name': GObject.ParamSpec.string(
            'icon-name',
            'Category Icon Name', 'Category Icon Name',
            GObject.ParamFlags.READWRITE,
            '',
        ),
    },
}, class SidebarRow extends Gtk.ListBoxRow {
    _init() {
        super._init({
            accessible_role: Gtk.AccessibleRole.ROW,
        });
        let hbox = new Gtk.Box({
            orientation: Gtk.Orientation.HORIZONTAL,
            margin_top: 12,
            margin_bottom: 12,
            margin_start: 6,
            margin_end: 6,
            spacing: 12,
        });

        let image = new Gtk.Image();
        this.bind_property('icon-name', image, 'icon-name',
            GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE,
        );
        image.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR);
        hbox.append(image);

        let label = new Gtk.Label({ halign: Gtk.Align.START });
        this.bind_property('title', label, 'label',
            GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE,
        );
        // Because bind_property doesn't work with transform functions
        // TODO: is this really needed?
        this.connect('notify::title', row => {
            row.tooltip_text = _('%s Sidebar Row').format(row.title);
        });
        hbox.append(label);

        this.set_child(hbox);
    }

    get title() {
        return this._title || '';
    }

    set title(title) {
        this._title = title;
    }

    get category() {
        return this._category || Gc.Category.NONE;
    }

    set category(value) {
        this._category = value;
    }
});

<|endoftext|>