<commit_before>/**
 * @fileoverview This module provides some functions to check the type of variable
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 * @dependency collection.js
 */

'use strict';

var toString = Object.prototype.toString;

/**
 * Check whether the given variable is existing or not.

 *  If the given variable is not null and not undefined, returns true.
 * @param {*} param - Target for checking
 * @returns {boolean} Is existy?
 * @memberof tui.util
 * @example
 *  tui.util.isExisty(''); //true
 *  tui.util.isExisty(0); //true
 *  tui.util.isExisty([]); //true
 *  tui.util.isExisty({}); //true
 *  tui.util.isExisty(null); //false
 *  tui.util.isExisty(undefined); //false
*/
function isExisty(param) {
    return !isUndefined(param) && !isNull(param);
}

/**
 * Check whether the given variable is undefined or not.

 *  If the given variable is undefined, returns true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is undefined?
 * @memberof tui.util
 */
function isUndefined(obj) {
    return obj === undefined; // eslint-disable-line no-undefined
}

/**
 * Check whether the given variable is null or not.

 *  If the given variable(arguments[0]) is null, returns true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is null?
 * @memberof tui.util
 */
function isNull(obj) {
    return obj === null;
}

/**
 * Check whether the given variable is truthy or not.

 *  If the given variable is not null or not undefined or not false, returns true.

 *  (It regards 0 as true)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is truthy?
 * @memberof tui.util
 */
function isTruthy(obj) {
    return isExisty(obj) && obj !== false;
}

/**
 * Check whether the given variable is falsy or not.

 *  If the given variable is null or undefined or false, returns true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is falsy?
 * @memberof tui.util
 */
function isFalsy(obj) {
    return !isTruthy(obj);
}

/**
 * Check whether the given variable is an arguments object or not.

 *  If the given variable is an arguments object, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is arguments?
 * @memberof tui.util
 */
function isArguments(obj) {
    var result = isExisty(obj) &&
        ((toString.call(obj) === '[object Arguments]') || !!obj.callee);

    return result;
}

/**
 * Check whether the given variable is an instance of Array or not.

 *  If the given variable is an instance of Array, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is array instance?
 * @memberof tui.util
 */
function isArray(obj) {
    return obj instanceof Array;
}

/**
 * Check whether the given variable is an object or not.

 *  If the given variable is an object, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is object?
 * @memberof tui.util
 */
function isObject(obj) {
    return obj === Object(obj);
}

/**
 * Check whether the given variable is a function or not.

 *  If the given variable is a function, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is function?
 * @memberof tui.util
 */
function isFunction(obj) {
    return obj instanceof Function;
}

/**
 * Check whether the given variable is a number or not.

 *  If the given variable is a number, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is number?
 * @memberof tui.util
 */
function isNumber(obj) {
    return typeof obj === 'number' || obj instanceof Number;
}

/**
 * Check whether the given variable is a string or not.

 *  If the given variable is a string, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is string?
 * @memberof tui.util
 */
function isString(obj) {
    return typeof obj === 'string' || obj instanceof String;
}

/**
 * Check whether the given variable is a boolean or not.

 *  If the given variable is a boolean, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is boolean?
 * @memberof tui.util
 */
function isBoolean(obj) {
    return typeof obj === 'boolean' || obj instanceof Boolean;
}

/**
 * Check whether the given variable is an instance of Array or not.

 *  If the given variable is an instance of Array, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is an instance of array?
 * @memberof tui.util
 */
function isArraySafe(obj) {
    return toString.call(obj) === '[object Array]';
}

/**
 * Check whether the given variable is a function or not.

 *  If the given variable is a function, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a function?
 * @memberof tui.util
 */
function isFunctionSafe(obj) {
    return toString.call(obj) === '[object Function]';
}

/**
 * Check whether the given variable is a number or not.

 *  If the given variable is a number, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a number?
 * @memberof tui.util
 */
function isNumberSafe(obj) {
    return toString.call(obj) === '[object Number]';
}

/**
 * Check whether the given variable is a string or not.

 *  If the given variable is a string, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a string?
 * @memberof tui.util
 */
function isStringSafe(obj) {
    return toString.call(obj) === '[object String]';
}

/**
 * Check whether the given variable is a boolean or not.

 *  If the given variable is a boolean, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a boolean?
 * @memberof tui.util
 */
function isBooleanSafe(obj) {
    return toString.call(obj) === '[object Boolean]';
}

/**
 * Check whether the given variable is a instance of HTMLNode or not.

 *  If the given variables is a instance of HTMLNode, return true.
 * @param {*} html - Target for checking
 * @returns {boolean} Is HTMLNode ?
 * @memberof tui.util
 */
function isHTMLNode(html) {
    if (typeof HTMLElement === 'object') {
        return (html && (html instanceof HTMLElement || !!html.nodeType));
    }
    return !!(html && html.nodeType);
}

/**
 * Check whether the given variable is a HTML tag or not.

 *  If the given variables is a HTML tag, return true.
 * @param {*} html - Target for checking
 * @returns {Boolean} Is HTML tag?
 * @memberof tui.util
 */
function isHTMLTag(html) {
    if (typeof HTMLElement === 'object') {
        return (html && (html instanceof HTMLElement));
    }
    return !!(html && html.nodeType && html.nodeType === 1);
}

/**
 * Check whether the given variable is empty(null, undefined, or empty array, empty object) or not.

 *  If the given variables is empty, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is empty?
 * @memberof tui.util
 */
function isEmpty(obj) {
    return (!isExisty(obj) ||
        (isString(obj) && _isEmptyString(obj)) ||
        (isArray(obj) && _isEmptyArray(obj)) ||
        (isObject(obj) && (isFunction(obj) || _isEmptyObject(obj)))
    );
}

/**
 * Check string is empty
 * @private
 * @param {string} str - string
 * @returns {boolean} Is empty?
 */
function _isEmptyString(str) {
    return str === '';
}

/**
 * Check array or array like object is empty
 * @private
 * @param {...Array} arr - array
 * @returns {boolean} Is empty?
 */
function _isEmptyArray(arr) {
    return arr.length === 0;
}

/**
 * Check object is empty
 * @private
 * @param {Object} obj - object
 * @returns {boolean} Is empty?
 */
function _isEmptyObject(obj) {
    var key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            return false;
        }
    }

    return true;
}

/**
 * Check whether the given variable is not empty
 * (not null, not undefined, or not empty array, not empty object) or not.

 *  If the given variables is not empty, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is not empty?
 * @memberof tui.util
 */
function isNotEmpty(obj) {
    return !isEmpty(obj);
}

/**
 * Check whether the given variable is an instance of Date or not.

 *  If the given variables is an instance of Date, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is an instance of Date?
 * @memberof tui.util
 */
function isDate(obj) {
    return obj instanceof Date;
}

/**
 * Check whether the given variable is an instance of Date or not.

 *  If the given variables is an instance of Date, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is an instance of Date?
 * @memberof tui.util
 */
function isDateSafe(obj) {
    return toString.call(obj) === '[object Date]';
}

module.exports = {
    isExisty: isExisty,
    isUndefined: isUndefined,
    isNull: isNull,
    isTruthy: isTruthy,
    isFalsy: isFalsy,
    isArguments: isArguments,
    isArray: isArray,
    isArraySafe: isArraySafe,
    isObject: isObject,
    isFunction: isFunction,
    isFunctionSafe: isFunctionSafe,
    isNumber: isNumber,
    isNumberSafe: isNumberSafe,
    isDate: isDate,
    isDateSafe: isDateSafe,
    isString: isString,
    isStringSafe: isStringSafe,
    isBoolean: isBoolean,
    isBooleanSafe: isBooleanSafe,
    isHTMLNode: isHTMLNode,
    isHTMLTag: isHTMLTag,
    isEmpty: isEmpty,
    isNotEmpty: isNotEmpty
};
<commit_msg>fix: IE8 isEmpty() on un assigned variable<commit_after>/**
 * @fileoverview This module provides some functions to check the type of variable
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 * @dependency collection.js
 */

'use strict';

var collection = require('./collection');
var toString = Object.prototype.toString;

/**
 * Check whether the given variable is existing or not.

 *  If the given variable is not null and not undefined, returns true.
 * @param {*} param - Target for checking
 * @returns {boolean} Is existy?
 * @memberof tui.util
 * @example
 *  tui.util.isExisty(''); //true
 *  tui.util.isExisty(0); //true
 *  tui.util.isExisty([]); //true
 *  tui.util.isExisty({}); //true
 *  tui.util.isExisty(null); //false
 *  tui.util.isExisty(undefined); //false
*/
function isExisty(param) {
    return !isUndefined(param) && !isNull(param);
}

/**
 * Check whether the given variable is undefined or not.

 *  If the given variable is undefined, returns true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is undefined?
 * @memberof tui.util
 */
function isUndefined(obj) {
    return obj === undefined; // eslint-disable-line no-undefined
}

/**
 * Check whether the given variable is null or not.

 *  If the given variable(arguments[0]) is null, returns true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is null?
 * @memberof tui.util
 */
function isNull(obj) {
    return obj === null;
}

/**
 * Check whether the given variable is truthy or not.

 *  If the given variable is not null or not undefined or not false, returns true.

 *  (It regards 0 as true)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is truthy?
 * @memberof tui.util
 */
function isTruthy(obj) {
    return isExisty(obj) && obj !== false;
}

/**
 * Check whether the given variable is falsy or not.

 *  If the given variable is null or undefined or false, returns true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is falsy?
 * @memberof tui.util
 */
function isFalsy(obj) {
    return !isTruthy(obj);
}

/**
 * Check whether the given variable is an arguments object or not.

 *  If the given variable is an arguments object, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is arguments?
 * @memberof tui.util
 */
function isArguments(obj) {
    var result = isExisty(obj) &&
        ((toString.call(obj) === '[object Arguments]') || !!obj.callee);

    return result;
}

/**
 * Check whether the given variable is an instance of Array or not.

 *  If the given variable is an instance of Array, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is array instance?
 * @memberof tui.util
 */
function isArray(obj) {
    return obj instanceof Array;
}

/**
 * Check whether the given variable is an object or not.

 *  If the given variable is an object, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is object?
 * @memberof tui.util
 */
function isObject(obj) {
    return obj === Object(obj);
}

/**
 * Check whether the given variable is a function or not.

 *  If the given variable is a function, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is function?
 * @memberof tui.util
 */
function isFunction(obj) {
    return obj instanceof Function;
}

/**
 * Check whether the given variable is a number or not.

 *  If the given variable is a number, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is number?
 * @memberof tui.util
 */
function isNumber(obj) {
    return typeof obj === 'number' || obj instanceof Number;
}

/**
 * Check whether the given variable is a string or not.

 *  If the given variable is a string, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is string?
 * @memberof tui.util
 */
function isString(obj) {
    return typeof obj === 'string' || obj instanceof String;
}

/**
 * Check whether the given variable is a boolean or not.

 *  If the given variable is a boolean, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is boolean?
 * @memberof tui.util
 */
function isBoolean(obj) {
    return typeof obj === 'boolean' || obj instanceof Boolean;
}

/**
 * Check whether the given variable is an instance of Array or not.

 *  If the given variable is an instance of Array, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is an instance of array?
 * @memberof tui.util
 */
function isArraySafe(obj) {
    return toString.call(obj) === '[object Array]';
}

/**
 * Check whether the given variable is a function or not.

 *  If the given variable is a function, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a function?
 * @memberof tui.util
 */
function isFunctionSafe(obj) {
    return toString.call(obj) === '[object Function]';
}

/**
 * Check whether the given variable is a number or not.

 *  If the given variable is a number, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a number?
 * @memberof tui.util
 */
function isNumberSafe(obj) {
    return toString.call(obj) === '[object Number]';
}

/**
 * Check whether the given variable is a string or not.

 *  If the given variable is a string, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a string?
 * @memberof tui.util
 */
function isStringSafe(obj) {
    return toString.call(obj) === '[object String]';
}

/**
 * Check whether the given variable is a boolean or not.

 *  If the given variable is a boolean, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is a boolean?
 * @memberof tui.util
 */
function isBooleanSafe(obj) {
    return toString.call(obj) === '[object Boolean]';
}

/**
 * Check whether the given variable is a instance of HTMLNode or not.

 *  If the given variables is a instance of HTMLNode, return true.
 * @param {*} html - Target for checking
 * @returns {boolean} Is HTMLNode ?
 * @memberof tui.util
 */
function isHTMLNode(html) {
    if (typeof HTMLElement === 'object') {
        return (html && (html instanceof HTMLElement || !!html.nodeType));
    }
    return !!(html && html.nodeType);
}

/**
 * Check whether the given variable is a HTML tag or not.

 *  If the given variables is a HTML tag, return true.
 * @param {*} html - Target for checking
 * @returns {Boolean} Is HTML tag?
 * @memberof tui.util
 */
function isHTMLTag(html) {
    if (typeof HTMLElement === 'object') {
        return (html && (html instanceof HTMLElement));
    }
    return !!(html && html.nodeType && html.nodeType === 1);
}

/**
 * Check whether the given variable is empty(null, undefined, or empty array, empty object) or not.

 *  If the given variables is empty, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is empty?
 * @memberof tui.util
 */
function isEmpty(obj) {
    var hasKey = false;

    if (!isExisty(obj)) {
        return true;
    }

    if (isString(obj) && obj === '') {
        return true;
    }

    if (isArray(obj) || isArguments(obj)) {
        return obj.length === 0;
    }

    if (isObject(obj) && !isFunction(obj)) {
        collection.forEachOwnProperties(obj, function() {
            hasKey = true;
            return false;
        });

        return !hasKey;
    }

    return true;
}

/**
 * Check whether the given variable is not empty
 * (not null, not undefined, or not empty array, not empty object) or not.

 *  If the given variables is not empty, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is not empty?
 * @memberof tui.util
 */
function isNotEmpty(obj) {
    return !isEmpty(obj);
}

/**
 * Check whether the given variable is an instance of Date or not.

 *  If the given variables is an instance of Date, return true.
 * @param {*} obj - Target for checking
 * @returns {boolean} Is an instance of Date?
 * @memberof tui.util
 */
function isDate(obj) {
    return obj instanceof Date;
}

/**
 * Check whether the given variable is an instance of Date or not.

 *  If the given variables is an instance of Date, return true.

 *  (It is used for multiple frame environments)
 * @param {*} obj - Target for checking
 * @returns {boolean} Is an instance of Date?
 * @memberof tui.util
 */
function isDateSafe(obj) {
    return toString.call(obj) === '[object Date]';
}

module.exports = {
    isExisty: isExisty,
    isUndefined: isUndefined,
    isNull: isNull,
    isTruthy: isTruthy,
    isFalsy: isFalsy,
    isArguments: isArguments,
    isArray: isArray,
    isArraySafe: isArraySafe,
    isObject: isObject,
    isFunction: isFunction,
    isFunctionSafe: isFunctionSafe,
    isNumber: isNumber,
    isNumberSafe: isNumberSafe,
    isDate: isDate,
    isDateSafe: isDateSafe,
    isString: isString,
    isStringSafe: isStringSafe,
    isBoolean: isBoolean,
    isBooleanSafe: isBooleanSafe,
    isHTMLNode: isHTMLNode,
    isHTMLTag: isHTMLTag,
    isEmpty: isEmpty,
    isNotEmpty: isNotEmpty
};
<|endoftext|>


<commit_before>import APIClient from "./apiclient";
import {getId, getDuration, getPoints, getYoutubeId} from "./data/topic-tree-helper";
import _ from "underscore";
import Util from "./util";
import {editorForPath} from "./renderer";
import Immutable from "immutable";

const userInfoLocalStorageName = "userInfo-3";

export const signIn = () => APIClient.signIn();
export const signOut = (editUser) => {
    localStorage.removeItem(userInfoLocalStorageName);

    editUser((user) => user.merge({
        userInfo: null,
        startedEntityIds: [],
        completedEntityIds: [],
    }));

    return APIClient.signOut();
};

export const isSignedIn = () =>
    APIClient.isSignedIn();

const getLocalStorageName = (base, userInfo) =>
    base + "-uid-" + (userInfo.get("nickname") || userInfo.get("username"));

const completedEntityIdsLocalStorageName = _.partial(getLocalStorageName, "completed");
const startedEntityIdsLocalStorageName = _.partial(getLocalStorageName, "started");
const userVideosLocalStorageName = _.partial(getLocalStorageName, "userVideos");
const userExercisesLocalStorageName = _.partial(getLocalStorageName, "userExercises");

const saveUserInfo = (userInfo) => {
    localStorage.removeItem(userInfoLocalStorageName);
    localStorage.setItem(userInfoLocalStorageName, JSON.stringify(userInfo));
};

const saveStarted = (userInfo, startedEntityIds) => {
    localStorage.removeItem(startedEntityIdsLocalStorageName(userInfo));
    localStorage.setItem(startedEntityIdsLocalStorageName(userInfo), JSON.stringify(startedEntityIds));
};

const saveCompleted = (userInfo, completedEntityIds) => {
    localStorage.removeItem(completedEntityIdsLocalStorageName(userInfo));
    localStorage.setItem(completedEntityIdsLocalStorageName(userInfo), JSON.stringify(completedEntityIds));
};

const saveUserVideos = (userInfo, userVideos) => {
    userVideos = userVideos.map((userVideo) => {
        return {
            duration: userVideo.duration,
            last_second_watched: userVideo.last_second_watched,
            points: userVideo.points,
            video: {
                id: userVideo.id
            }
        };
    });
    localStorage.removeItem(userVideosLocalStorageName(userInfo));
    localStorage.setItem(userVideosLocalStorageName(userInfo), JSON.stringify(userVideos));
};

const saveUserExercises = (userInfo, userExercises) => {
    userExercises = userExercises.map((exercise) => {
        return {
            streak: exercise.streak,
            total_correct: exercise.total_correct,
            total_done: exercise.total_done,
            exercise_model: {
                content_id: exercise.exercise_model.content_id
            }
        };
    });

    // The extra removeItem calls before the setItem calls help in case local storage is almost full
    localStorage.removeItem(userExercisesLocalStorageName(userInfo));
    localStorage.setItem(userExercisesLocalStorageName(userInfo), JSON.stringify(userExercises));
};

const loadLocalStorageData = (userInfo) => {
    var result = {};
    var completedEntityIds = localStorage.getItem(completedEntityIdsLocalStorageName(userInfo));
    if (completedEntityIds) {
        result.completedEntityIds = JSON.parse(completedEntityIds);
    }
    var startedEntityIds = localStorage.getItem(startedEntityIdsLocalStorageName(userInfo));
    if (startedEntityIds) {
        result.startedEntityIds = JSON.parse(startedEntityIds);
    }
    var userVideos = localStorage.getItem(userVideosLocalStorageName(userInfo));
    if (userVideos) {
        result.userVideos = JSON.parse(userVideos);
    }
    var userExercises = localStorage.getItem(userExercisesLocalStorageName(userInfo));
    if (userExercises) {
        result.userExercises = JSON.parse(userExercises);
    }

    return result;
};

export const reportVideoProgress = (user, topicTreeNode, secondsWatched, lastSecondWatched, editVideo, editUser) => {
    return new Promise((resolve, reject) => {
        const youTubeId = getYoutubeId(topicTreeNode),
            videoId = getId(topicTreeNode),
            duration = getDuration(topicTreeNode),
            editCompletedEntityIds = editorForPath(editUser, "completedEntityIds"),
            editStartedEntityIds = editorForPath(editUser, "startedEntityIds"),
            editUserInfo = editorForPath(editUser, "userInfo"),
            editUserVideos = editorForPath(editUser, "userVideos");
        let completedEntityIds = user.get("completedEntityIds"),
            startedEntityIds = user.get("startedEntityIds"),
            userVideos = user.get("userVideos");

        APIClient.reportVideoProgress(videoId, youTubeId, secondsWatched, lastSecondWatched).then((result) => {
            if (!result) {
                Util.warn("Video progress report returned null results!");
                return;
            }
            Util.log("reportVideoProgress result: %o", result);

            var lastPoints = getPoints(topicTreeNode);
            var newPoints = lastPoints + result.points_earned;
            if (newPoints > 750) {
                newPoints = 750;
            }

            // If they've watched some part of the video, and it's not almost the end
            // Otherwise check if we already have video progress for this item and we
            // therefore no longer need it.
            var lastSecondWatched;
            if (result.last_second_watched > 10 &&
                    duration - result.last_second_watched > 10) {
                lastSecondWatched = result.last_second_watched;
            }

            // If we're just getting a completion of a video update
            // the user's overall points locally.
            if (result.points_earned > 0) {
                var userInfo = user.get("userInfo");
                userInfo = userInfo.set("points",
                    userInfo.get("points") + result.points_earned);
                editUserInfo(() => userInfo);
                saveUserInfo(userInfo);
            }

            editVideo((video) =>
                video.merge({
                    points: newPoints,
                    completed: result.is_video_completed,
                    started: !result.is_video_completed,
                    lastSecondWatched: lastSecondWatched
                }));

            // Update locally stored cached info
            if (result.is_video_completed) {
                if (startedEntityIds.contains(getId(topicTreeNode))) {
                    startedEntityIds = startedEntityIds.remove(startedEntityIds.indexOf(getId(topicTreeNode)));
                    editStartedEntityIds(() => startedEntityIds);
                }
                if (!completedEntityIds.contains(getId(topicTreeNode))) {
                    completedEntityIds = completedEntityIds.unshift(getId(topicTreeNode));
                    editCompletedEntityIds(() => completedEntityIds);
                }
            } else {
                if (!startedEntityIds.contains(getId(topicTreeNode))) {
                    startedEntityIds = startedEntityIds.unshift(getId(topicTreeNode));
                    editStartedEntityIds(() => startedEntityIds);
                }
            }

            var foundUserVideo = userVideos.find((info) =>
                info.getIn(["video", "id"]) === getId(topicTreeNode));
            if (foundUserVideo) {
                foundUserVideo = foundUserVideo.toJS();
            }
            var isNew = !foundUserVideo;
            foundUserVideo = foundUserVideo || {
                video: {
                    id: getId(topicTreeNode)
                },
                duration: getDuration(topicTreeNode)
            };
            foundUserVideo["points"] = newPoints;
            foundUserVideo["last_second_watched"] = lastSecondWatched;
            if (isNew) {
                userVideos = userVideos.unshift(Immutable.fromJS(foundUserVideo));
                editUserVideos(() => userVideos);
            }

            saveStarted(user.get("userInfo"), startedEntityIds);
            saveCompleted(user.get("userInfo"), completedEntityIds);
            saveUserVideos(user.get("userInfo"), userVideos);

            resolve({
                completed: result.is_video_completed,
                lastSecondWatched: result.last_second_watched,
                pointsEarned: result.points_earned,
                youtubeId: result.youtube_id,
                videoId,
                id: getId(topicTreeNode)
            });
        }).catch(() => {
            reject();
        });
    });
};

export const reportArticleRead = (user, topicTreeNode, editUser) => {
    return new Promise((resolve, reject) => {
        if (!isSignedIn()) {
            return setTimeout(resolve, 0);
        }

        APIClient.reportArticleRead(getId(topicTreeNode)).then((result) => {
            Util.log("reported article complete: %o", result);
            let completedEntityIds = user.get("completedEntityIds");
            if (!completedEntityIds.contains(getId(topicTreeNode))) {
              completedEntityIds = completedEntityIds.unshift(getId(topicTreeNode));
              const editCompletedEntityIds = editorForPath(editUser, "completedEntityIds");
              editCompletedEntityIds(() => completedEntityIds);
            }
            saveCompleted(user.get("userInfo"), completedEntityIds);
            resolve(result);
        }).catch(() => {
            reject();
        });
    });
};

export const refreshLoggedInInfo = (user, editUser, forceRefreshAllInfo) => {
    return new Promise((resolve, reject) => {
        if (!isSignedIn()) {
            return resolve();
        }

        // Get the user profile info
        APIClient.getUserInfo().then((result) => {
            Util.log("getUserInfo: %o", result);
            const userInfo = Immutable.fromJS({
                avatarUrl: result.avatar_url,
                joined: result.joined,
                nickname: result.nickname,
                username: result.username,
                points: result.points,
                badgeCounts: result.badge_counts
            });

            editUser((user) => user.set("userInfo", userInfo));

            saveUserInfo(userInfo.toJS());

            var result = loadLocalStorageData(userInfo);
            if (!forceRefreshAllInfo && result.completedEntityIds) {
                Util.log("User info only obtained. Not obtaining user data because we have it cached already!");
                return result;
            }

            // The call is needed for completed/in progress status of content items
            // Unlike getUserVideos, this includes both articles and videos.
            return APIClient.getUserProgress();

        }).then((data) => {
            Util.log("getUserProgress: %o", data);
            // data.complete will be returned from the API but not when loaded
            // directly from localStorage.  When loaded directly from localstorage
            // you'll already have result.startedEntityIds.
            if (data.complete) {
                // Get rid of the 'a' and 'v' prefixes, and set the completed / started
                // attributes accordingly.
                data.startedEntityIds = _.map(data.started, function(e) {
                    return e.substring(1);
                });
                data.completedEntityIds = _.map(data.complete, function(e) {
                    return e.substring(1);
                });

                // Save to local storage
                saveStarted(user.get("userInfo"), data.startedEntityIds);
                saveCompleted(user.get("userInfo"), data.completedEntityIds);
            }

            editUser((user) => user.merge({
                startedEntityIds: data.startedEntityIds,
                completedEntityIds: data.completedEntityIds,
            }));

            return APIClient.getUserVideos();
        }).then((userVideosResults) => {
            saveUserVideos(user.get("userInfo"), userVideosResults);
            return APIClient.getUserExercises();
        }).then((userExercisesResults) => {
            saveUserExercises(user.get("userInfo"), userExercisesResults);
            resolve();
        }).catch(() => {
            reject();
        });
    });
};

<commit_msg>Add some documentation<commit_after>import APIClient from "./apiclient";
import {getId, getDuration, getPoints, getYoutubeId} from "./data/topic-tree-helper";
import _ from "underscore";
import Util from "./util";
import {editorForPath} from "./renderer";
import Immutable from "immutable";

const userInfoLocalStorageName = "userInfo-3";

/**
 * Signs the user in by redirecting them to the KA auth page
 */
export const signIn = () => APIClient.signIn();

/**
 * Signs the user out and resets user data back to empty
 */
export const signOut = (editUser) => {
    localStorage.removeItem(userInfoLocalStorageName);

    editUser((user) => user.merge({
        userInfo: null,
        startedEntityIds: [],
        completedEntityIds: [],
    }));

    return APIClient.signOut();
};

/**
 * Determines if a user is signed in or not
 */
export const isSignedIn = () =>
    APIClient.isSignedIn();

const getLocalStorageName = (base, userInfo) =>
    base + "-uid-" + (userInfo.get("nickname") || userInfo.get("username"));

const completedEntityIdsLocalStorageName = _.partial(getLocalStorageName, "completed");
const startedEntityIdsLocalStorageName = _.partial(getLocalStorageName, "started");
const userVideosLocalStorageName = _.partial(getLocalStorageName, "userVideos");
const userExercisesLocalStorageName = _.partial(getLocalStorageName, "userExercises");

/**
 * Saves a userInfo object (not ImmutableJS)
 */
const saveUserInfo = (userInfo) => {
    localStorage.removeItem(userInfoLocalStorageName);
    localStorage.setItem(userInfoLocalStorageName, JSON.stringify(userInfo));
};

/**
 * Saves a list of started entities (not ImmutableJS)
 */
const saveStarted = (userInfo, startedEntityIds) => {
    localStorage.removeItem(startedEntityIdsLocalStorageName(userInfo));
    localStorage.setItem(startedEntityIdsLocalStorageName(userInfo), JSON.stringify(startedEntityIds));
};

/**
 * Saves a list of completed entities (not ImmutableJS)
 */
const saveCompleted = (userInfo, completedEntityIds) => {
    localStorage.removeItem(completedEntityIdsLocalStorageName(userInfo));
    localStorage.setItem(completedEntityIdsLocalStorageName(userInfo), JSON.stringify(completedEntityIds));
};

/**
 * Saves a list of user entities (not ImmutableJS).
 * THis is mostly used for tracking the last position of the watched video.
 */
const saveUserVideos = (userInfo, userVideos) => {
    userVideos = userVideos.map((userVideo) => {
        return {
            duration: userVideo.duration,
            last_second_watched: userVideo.last_second_watched,
            points: userVideo.points,
            video: {
                id: userVideo.id
            }
        };
    });
    localStorage.removeItem(userVideosLocalStorageName(userInfo));
    localStorage.setItem(userVideosLocalStorageName(userInfo), JSON.stringify(userVideos));
};

/**
 * Saves a list of information on the exercise.
 */
const saveUserExercises = (userInfo, userExercises) => {
    userExercises = userExercises.map((exercise) => {
        return {
            streak: exercise.streak,
            total_correct: exercise.total_correct,
            total_done: exercise.total_done,
            exercise_model: {
                content_id: exercise.exercise_model.content_id
            }
        };
    });

    // The extra removeItem calls before the setItem calls help in case local storage is almost full
    localStorage.removeItem(userExercisesLocalStorageName(userInfo));
    localStorage.setItem(userExercisesLocalStorageName(userInfo), JSON.stringify(userExercises));
};

/**
 * Loads all of the different types of user data from local storage.
 */
const loadLocalStorageData = (userInfo) => {
    var result = {};
    var completedEntityIds = localStorage.getItem(completedEntityIdsLocalStorageName(userInfo));
    if (completedEntityIds) {
        result.completedEntityIds = JSON.parse(completedEntityIds);
    }
    var startedEntityIds = localStorage.getItem(startedEntityIdsLocalStorageName(userInfo));
    if (startedEntityIds) {
        result.startedEntityIds = JSON.parse(startedEntityIds);
    }
    var userVideos = localStorage.getItem(userVideosLocalStorageName(userInfo));
    if (userVideos) {
        result.userVideos = JSON.parse(userVideos);
    }
    var userExercises = localStorage.getItem(userExercisesLocalStorageName(userInfo));
    if (userExercises) {
        result.userExercises = JSON.parse(userExercises);
    }

    return result;
};

/**
 * Reports video progress for the user back to KA
 */
export const reportVideoProgress = (user, topicTreeNode, secondsWatched, lastSecondWatched, editVideo, editUser) => {
    return new Promise((resolve, reject) => {
        const youTubeId = getYoutubeId(topicTreeNode),
            videoId = getId(topicTreeNode),
            duration = getDuration(topicTreeNode),
            editCompletedEntityIds = editorForPath(editUser, "completedEntityIds"),
            editStartedEntityIds = editorForPath(editUser, "startedEntityIds"),
            editUserInfo = editorForPath(editUser, "userInfo"),
            editUserVideos = editorForPath(editUser, "userVideos");
        let completedEntityIds = user.get("completedEntityIds"),
            startedEntityIds = user.get("startedEntityIds"),
            userVideos = user.get("userVideos");

        APIClient.reportVideoProgress(videoId, youTubeId, secondsWatched, lastSecondWatched).then((result) => {
            if (!result) {
                Util.warn("Video progress report returned null results!");
                return;
            }
            Util.log("reportVideoProgress result: %o", result);

            var lastPoints = getPoints(topicTreeNode);
            var newPoints = lastPoints + result.points_earned;
            if (newPoints > 750) {
                newPoints = 750;
            }

            // If they've watched some part of the video, and it's not almost the end
            // Otherwise check if we already have video progress for this item and we
            // therefore no longer need it.
            var lastSecondWatched;
            if (result.last_second_watched > 10 &&
                    duration - result.last_second_watched > 10) {
                lastSecondWatched = result.last_second_watched;
            }

            // If we're just getting a completion of a video update
            // the user's overall points locally.
            if (result.points_earned > 0) {
                var userInfo = user.get("userInfo");
                userInfo = userInfo.set("points",
                    userInfo.get("points") + result.points_earned);
                editUserInfo(() => userInfo);
                saveUserInfo(userInfo);
            }

            editVideo((video) =>
                video.merge({
                    points: newPoints,
                    completed: result.is_video_completed,
                    started: !result.is_video_completed,
                    lastSecondWatched: lastSecondWatched
                }));

            // Update locally stored cached info
            if (result.is_video_completed) {
                if (startedEntityIds.contains(getId(topicTreeNode))) {
                    startedEntityIds = startedEntityIds.remove(startedEntityIds.indexOf(getId(topicTreeNode)));
                    editStartedEntityIds(() => startedEntityIds);
                }
                if (!completedEntityIds.contains(getId(topicTreeNode))) {
                    completedEntityIds = completedEntityIds.unshift(getId(topicTreeNode));
                    editCompletedEntityIds(() => completedEntityIds);
                }
            } else {
                if (!startedEntityIds.contains(getId(topicTreeNode))) {
                    startedEntityIds = startedEntityIds.unshift(getId(topicTreeNode));
                    editStartedEntityIds(() => startedEntityIds);
                }
            }

            var foundUserVideo = userVideos.find((info) =>
                info.getIn(["video", "id"]) === getId(topicTreeNode));
            if (foundUserVideo) {
                foundUserVideo = foundUserVideo.toJS();
            }
            var isNew = !foundUserVideo;
            foundUserVideo = foundUserVideo || {
                video: {
                    id: getId(topicTreeNode)
                },
                duration: getDuration(topicTreeNode)
            };
            foundUserVideo["points"] = newPoints;
            foundUserVideo["last_second_watched"] = lastSecondWatched;
            if (isNew) {
                userVideos = userVideos.unshift(Immutable.fromJS(foundUserVideo));
                editUserVideos(() => userVideos);
            }

            saveStarted(user.get("userInfo"), startedEntityIds);
            saveCompleted(user.get("userInfo"), completedEntityIds);
            saveUserVideos(user.get("userInfo"), userVideos);

            resolve({
                completed: result.is_video_completed,
                lastSecondWatched: result.last_second_watched,
                pointsEarned: result.points_earned,
                youtubeId: result.youtube_id,
                videoId,
                id: getId(topicTreeNode)
            });
        }).catch(() => {
            reject();
        });
    });
};

/**
 * Reports article progress for the user back to KA
 */
export const reportArticleRead = (user, topicTreeNode, editUser) => {
    return new Promise((resolve, reject) => {
        if (!isSignedIn()) {
            return setTimeout(resolve, 0);
        }

        APIClient.reportArticleRead(getId(topicTreeNode)).then((result) => {
            Util.log("reported article complete: %o", result);
            let completedEntityIds = user.get("completedEntityIds");
            if (!completedEntityIds.contains(getId(topicTreeNode))) {
              completedEntityIds = completedEntityIds.unshift(getId(topicTreeNode));
              const editCompletedEntityIds = editorForPath(editUser, "completedEntityIds");
              editCompletedEntityIds(() => completedEntityIds);
            }
            saveCompleted(user.get("userInfo"), completedEntityIds);
            resolve(result);
        }).catch(() => {
            reject();
        });
    });
};

/**
 * Refreshes the logged in info either from local storage or from the server
 */
export const refreshLoggedInInfo = (user, editUser, forceRefreshAllInfo) => {
    return new Promise((resolve, reject) => {
        if (!isSignedIn()) {
            return resolve();
        }

        // Get the user profile info
        APIClient.getUserInfo().then((result) => {
            Util.log("getUserInfo: %o", result);
            const userInfo = Immutable.fromJS({
                avatarUrl: result.avatar_url,
                joined: result.joined,
                nickname: result.nickname,
                username: result.username,
                points: result.points,
                badgeCounts: result.badge_counts
            });

            editUser((user) => user.set("userInfo", userInfo));

            saveUserInfo(userInfo.toJS());

            var result = loadLocalStorageData(userInfo);
            if (!forceRefreshAllInfo && result.completedEntityIds) {
                Util.log("User info only obtained. Not obtaining user data because we have it cached already!");
                return result;
            }

            // The call is needed for completed/in progress status of content items
            // Unlike getUserVideos, this includes both articles and videos.
            return APIClient.getUserProgress();

        }).then((data) => {
            Util.log("getUserProgress: %o", data);
            // data.complete will be returned from the API but not when loaded
            // directly from localStorage.  When loaded directly from localstorage
            // you'll already have result.startedEntityIds.
            if (data.complete) {
                // Get rid of the 'a' and 'v' prefixes, and set the completed / started
                // attributes accordingly.
                data.startedEntityIds = _.map(data.started, function(e) {
                    return e.substring(1);
                });
                data.completedEntityIds = _.map(data.complete, function(e) {
                    return e.substring(1);
                });

                // Save to local storage
                saveStarted(user.get("userInfo"), data.startedEntityIds);
                saveCompleted(user.get("userInfo"), data.completedEntityIds);
            }

            editUser((user) => user.merge({
                startedEntityIds: data.startedEntityIds,
                completedEntityIds: data.completedEntityIds,
            }));

            return APIClient.getUserVideos();
        }).then((userVideosResults) => {
            saveUserVideos(user.get("userInfo"), userVideosResults);
            return APIClient.getUserExercises();
        }).then((userExercisesResults) => {
            saveUserExercises(user.get("userInfo"), userExercisesResults);
            resolve();
        }).catch(() => {
            reject();
        });
    });
};
<|endoftext|>


<commit_before>onmessage = function(e){
    const start = Date.now();
    const links = e.data.links;
    const dm = e.data.matrix;
    const labels = Object.keys(dm);
    const epsilon = Math.pow(10, e.data.epsilon);
    const metric = e.data.metric;
    const n = labels.length
    const m = links.length;
    let output = new Uint8Array(m);
    let matrix = [];
    let map = [];
    for (let i = 0; i < n; i++) {
        let minDist = Number.MAX_VALUE;
        let targets = [];
        const nodeid = labels[i];
        const row = dm[nodeid];
        for (let j = 0; j < n; j++) {
          let cell = row[labels[j]];
          if(!cell) {
            targets.push(0);
            continue;
          };
          let value = cell[metric];
          targets.push(value);
        }
        matrix.push(targets);
        map.push(nodeid);
    }

    const mst = primMST(matrix);
    const nng = nearest_neighbour_graph(matrix, mst, epsilon);

    for (let i = 0; i < n; i++) {
      const source = map[i];
        nng[i].push(mst[i]);
        Array.from(new Set(nng[i])).forEach((u, index) => {
          const target = map[u];
          for(let k = 0; k < m; k++){
            let l = links[k];
            if((l.source == source && l.target == target) || (l.source == target && l.target == source)) {
              output[k] = 1;
            }
          }
        })
    }
    console.log('MST Compute time: ', (Date.now()-start).toLocaleString(), 'ms');
    postMessage({links: output.buffer, start: Date.now()}, [output.buffer]);
    close();
};

const minKey = (key, mstSet, V) => {
    let min = Number.MAX_VALUE;
    let min_index = -1;
    for (let v = 0; v < V; v++)
        if (!mstSet[v] && key[v] < min) {
            min = key[v];
            min_index = v;
        }
    return min_index;
}

const primMST = (graph) => {
    const V = graph.length;
    let parent = [];
    let key = [];
    let mstSet = [];
    for (let i = 0; i < V; i++) {
        key[i] = Number.MAX_VALUE;
        mstSet[i] = false;
    }
    key[0] = 0.0;
    parent[0] = -1;
    for (let count = 0; count < V-1; count++) {
        let u = minKey(key, mstSet, V);
        if (u < 0) continue;
        mstSet[u] = true;

        if (graph[u].reduce((a, b) => a + b, 0) === 0 && u != 0) continue;

        for (let v = 0; v < V; v++) {
            if (graph[u][v] >= 0 && !mstSet[v] && graph[u][v] <  key[v]) {
                parent[v]  = u;
                key[v] = graph[u][v];
            }
        }
    }
    return parent;
}

const nearest_neighbour_graph = (graph, mst_parents, epsilon) => {
  const V = graph.length;
  let mst = [];
  for (let i=0; i<V; ++i) {
    mst.push([]);
  }
  for (let i=1; i<V; ++i) {
    mst[i].push(mst_parents[i]);
    mst[mst_parents[i]].push(i);
  }
  let nng = [];
  let longest_edge = [];
  for (let i=0; i<V; ++i) {
    nng.push([]);
    longest_edge.push([]);
    for (let j=0; j<V; ++j) {
        longest_edge[i][j] = 0;
    }
  }
  for (let i=0; i<V; ++i) {
    bfs_update_matrix(mst, graph, i, longest_edge);
  }
  for (let i=0; i<V; ++i) {
    for (let j=0; j<V; ++j) {
      if ((graph[i][j] > 0 ) && (graph[i][j] <= (longest_edge[i][j] * (1.0 + epsilon)))) {
          nng[i].push(j);
          nng[j].push(i);
      }
    }
  }
  return nng;
}

const bfs_update_matrix = (mst, weights, root, longest_edge) => {
  let visited = [];
  let queue = [];
  queue.push(root);
  while (queue.length) {
    let v = queue.shift();
    visited[v] = true;
    mst[v].forEach((u, index) => {
      if(visited[u]) return;
      queue.push(u);
      const value = Math.max(weights[v][u], Math.max(longest_edge[root][u], longest_edge[root][v]));
      longest_edge[root][u] = value;
      longest_edge[u][root] = value;
    })
  }
}<commit_msg>#206 consistent formatting<commit_after>onmessage = function(e){
    const start = Date.now();
    const links = e.data.links;
    const dm = e.data.matrix;
    const labels = Object.keys(dm);
    const epsilon = Math.pow(10, e.data.epsilon);
    const metric = e.data.metric;
    const n = labels.length
    const m = links.length;
    let output = new Uint8Array(m);
    let matrix = [];
    let map = [];
    for (let i = 0; i < n; i++) {
        let minDist = Number.MAX_VALUE;
        let targets = [];
        const nodeid = labels[i];
        const row = dm[nodeid];
        for (let j = 0; j < n; j++) {
          let cell = row[labels[j]];
          if(!cell) {
            targets.push(0);
            continue;
          };
          let value = cell[metric];
          targets.push(value);
        }
        matrix.push(targets);
        map.push(nodeid);
    }

    const mst = primMST(matrix);
    const nng = nearest_neighbour_graph(matrix, mst, epsilon);

    for (let i = 0; i < n; i++) {
      const source = map[i];
      nng[i].push(mst[i]);
      Array.from(new Set(nng[i])).forEach((u, index) => {
        const target = map[u];
        for(let k = 0; k < m; k++){
          let l = links[k];
          if((l.source == source && l.target == target) || (l.source == target && l.target == source)) {
            output[k] = 1;
          }
        }
      })
    }
    console.log('MST Compute time: ', (Date.now()-start).toLocaleString(), 'ms');
    postMessage({links: output.buffer, start: Date.now()}, [output.buffer]);
    close();
};

const minKey = (key, mstSet, V) => {
  let min = Number.MAX_VALUE;
  let min_index = -1;
  for (let v = 0; v < V; v++)
    if (!mstSet[v] && key[v] < min) {
        min = key[v];
        min_index = v;
    }
  return min_index;
}

const primMST = (graph) => {
  const V = graph.length;
  let parent = [];
  let key = [];
  let mstSet = [];
  for (let i = 0; i < V; i++) {
      key[i] = Number.MAX_VALUE;
      mstSet[i] = false;
  }
  key[0] = 0.0;
  parent[0] = -1;
  for (let count = 0; count < V-1; count++) {
      let u = minKey(key, mstSet, V);
      if (u < 0) continue;
      mstSet[u] = true;

      if (graph[u].reduce((a, b) => a + b, 0) === 0 && u != 0) continue;

      for (let v = 0; v < V; v++) {
          if (graph[u][v] >= 0 && !mstSet[v] && graph[u][v] <  key[v]) {
              parent[v]  = u;
              key[v] = graph[u][v];
          }
      }
  }
  return parent;
}

const nearest_neighbour_graph = (graph, mst_parents, epsilon) => {
  const V = graph.length;
  let mst = [];
  for (let i=0; i<V; ++i) {
    mst.push([]);
  }
  for (let i=1; i<V; ++i) {
    mst[i].push(mst_parents[i]);
    mst[mst_parents[i]].push(i);
  }
  let nng = [];
  let longest_edge = [];
  for (let i=0; i<V; ++i) {
    nng.push([]);
    longest_edge.push([]);
    for (let j=0; j<V; ++j) {
        longest_edge[i][j] = 0;
    }
  }
  for (let i=0; i<V; ++i) {
    bfs_update_matrix(mst, graph, i, longest_edge);
  }
  for (let i=0; i<V; ++i) {
    for (let j=0; j<V; ++j) {
      if ((graph[i][j] > 0 ) && (graph[i][j] <= (longest_edge[i][j] * (1.0 + epsilon)))) {
          nng[i].push(j);
          nng[j].push(i);
      }
    }
  }
  return nng;
}

const bfs_update_matrix = (mst, weights, root, longest_edge) => {
  let visited = [];
  let queue = [];
  queue.push(root);
  while (queue.length) {
    let v = queue.shift();
    visited[v] = true;
    mst[v].forEach((u, index) => {
      if(visited[u]) return;
      queue.push(u);
      const value = Math.max(weights[v][u], Math.max(longest_edge[root][u], longest_edge[root][v]));
      longest_edge[root][u] = value;
      longest_edge[u][root] = value;
    })
  }
}<|endoftext|>


<commit_before>var util = require('util');
var path = require('path');
var sh = require('shelljs');
var stream = require('stream');

// https://en.wikipedia.org/wiki/Java_logging_framework
var LogSeverity = {
    FATAL: 'FATAL',
    ERROR: 'ERROR',
    WARNING: 'WARNING',
    INFO: 'INFO',
    DEBUG: 'DEBUG',
    TRACE: 'TRACE'
};

// Logger =============================================================
function Logger(loggerName, fpaths) {
    if (!loggerName) {
        throw new Error("Logger loggerName must be supplied");
    }
    this.loggerName = loggerName;

    this.fpaths = [];
    if (fpaths && 'filter' in fpaths) {
        this.fpaths = fpaths.filter((fpath) => {
            var fpathDir = path.dirname(fpath);
            if (!require('./fs').isDirRW(fpathDir)) {
                console.error(util.format("No RW to dir `%s`", fpathDir));
                return false;
            }
            console.log(util.format('Logging to `%s`', fpath));
            return true;
        });
    }

    this.createDate = new Date();

    this.stdout = new stream.Writable({
        write: (chunk, encoding, next) => {
            process.stdout.write(chunk);
            this.write2fs(chunk);
            next();
        }
    });

    this.stderr = new stream.Writable({
        write: (chunk, encoding, next) => {
            process.stderr.write(chunk);
            this.write2fs(chunk);
            next();
        }
    });
}

Object.defineProperty(Logger.prototype, "constructor", {
    enumerable: false,
    value: Logger
});

Logger.prototype.outputFormatDefault = "[%s %s] %s %s\n";
Logger.prototype.outputDTOpts = {hour12: false };
Logger.prototype.outputDTLocale = 'en-US';

Logger.prototype.log = function (msg, severity, origin, filesOnly) {
    origin = origin ? origin : '';
    var LogDateStr = (new Date())
        .toLocaleString(this.outputDTLocale, this.outputDTOpts)
    var msg = util.format(this.outputFormatDefault, LogDateStr, origin,
        severity, msg);
    if (filesOnly) {
        this.write2fs(msg);
    }
    else {
        switch (severity) {
            case LogSeverity.FATAL:
            case LogSeverity.ERROR:
            case LogSeverity.WARNING:
                this.stderr.write(msg);
                break;
            case LogSeverity.INFO:
                this.stdout.write(msg);
                break;
            case LogSeverity.DEBUG:
            case LogSeverity.TRACE:
                this.write2fs(msg);
                break;
            default:
                console.error('Invalid logging severity level: ' + severity);
                process.stdout.write(msg);
        }
    }
};

Logger.prototype.write2fs = function (data) {
    data = data.toString();
    this.fpaths.forEach((fpath) => {
        data.toEnd(fpath);
        if (sh.error()) {
            var msg = util.format('Failed to write to log filepath `%s`\n',
                fpath);
            process.stderr.write(msg);
        }
    });
};
// End Logger =========================================================

// https://github.com/shelljs/shelljs/blob/0166658597a69a77b4d1343217b12e2a50ee2df3/src/common.js#L164
function randomFileName() {
    function randomHash(count) {
        if (count === 1)
            return parseInt(16*Math.random(), 10).toString(16);
        else {
            var hash = '';
            for (var i=0; i<count; i++)
                hash += randomHash(1);
            return hash;
        }
    }

    return 'syspol_'+randomHash(20);
}

exports.Logger = Logger;
exports.randomFileName = randomFileName;
exports.LogSeverity = LogSeverity;<commit_msg>syspol.util.Logger.log default severity is INFO<commit_after>var util = require('util');
var path = require('path');
var sh = require('shelljs');
var stream = require('stream');

// https://en.wikipedia.org/wiki/Java_logging_framework
var LogSeverity = {
    FATAL: 'FATAL',
    ERROR: 'ERROR',
    WARNING: 'WARNING',
    INFO: 'INFO',
    DEBUG: 'DEBUG',
    TRACE: 'TRACE'
};

// Logger =============================================================
function Logger(loggerName, fpaths) {
    if (!loggerName) {
        throw new Error("Logger loggerName must be supplied");
    }
    this.loggerName = loggerName;

    this.fpaths = [];
    if (fpaths && 'filter' in fpaths) {
        this.fpaths = fpaths.filter((fpath) => {
            var fpathDir = path.dirname(fpath);
            if (!require('./fs').isDirRW(fpathDir)) {
                console.error(util.format("No RW to dir `%s`", fpathDir));
                return false;
            }
            console.log(util.format('Logging to `%s`', fpath));
            return true;
        });
    }

    this.createDate = new Date();

    this.stdout = new stream.Writable({
        write: (chunk, encoding, next) => {
            process.stdout.write(chunk);
            this.write2fs(chunk);
            next();
        }
    });

    this.stderr = new stream.Writable({
        write: (chunk, encoding, next) => {
            process.stderr.write(chunk);
            this.write2fs(chunk);
            next();
        }
    });
}

Object.defineProperty(Logger.prototype, "constructor", {
    enumerable: false,
    value: Logger
});

Logger.prototype.outputFormatDefault = "[%s %s] %s %s\n";
Logger.prototype.outputDTOpts = {hour12: false };
Logger.prototype.outputDTLocale = 'en-US';

Logger.prototype.log = function (msg, severity, origin, filesOnly) {
    origin = origin ? origin : '';
    severity = severity ? severity : LogSeverity.INFO;
    var LogDateStr = (new Date())
        .toLocaleString(this.outputDTLocale, this.outputDTOpts)
    var msg = util.format(this.outputFormatDefault, LogDateStr, origin,
        severity, msg);
    if (filesOnly) {
        this.write2fs(msg);
    }
    else {
        switch (severity) {
            case LogSeverity.FATAL:
            case LogSeverity.ERROR:
            case LogSeverity.WARNING:
                this.stderr.write(msg);
                break;
            case LogSeverity.INFO:
                this.stdout.write(msg);
                break;
            case LogSeverity.DEBUG:
            case LogSeverity.TRACE:
                this.write2fs(msg);
                break;
            default:
                console.error('Invalid logging severity level: ' + severity);
                process.stdout.write(msg);
        }
    }
};

Logger.prototype.write2fs = function (data) {
    data = data.toString();
    this.fpaths.forEach((fpath) => {
        data.toEnd(fpath);
        if (sh.error()) {
            var msg = util.format('Failed to write to log filepath `%s`\n',
                fpath);
            process.stderr.write(msg);
        }
    });
};
// End Logger =========================================================

// https://github.com/shelljs/shelljs/blob/0166658597a69a77b4d1343217b12e2a50ee2df3/src/common.js#L164
function randomFileName() {
    function randomHash(count) {
        if (count === 1)
            return parseInt(16*Math.random(), 10).toString(16);
        else {
            var hash = '';
            for (var i=0; i<count; i++)
                hash += randomHash(1);
            return hash;
        }
    }

    return 'syspol_'+randomHash(20);
}

exports.Logger = Logger;
exports.randomFileName = randomFileName;
exports.LogSeverity = LogSeverity;
<|endoftext|>


<commit_before>// node.js imports
import { join, dirname, relative } from 'path'
import { statSync, lstatSync, readdirSync } from 'fs'
import { start, change_sequence as changeSeq } from 'simple-spinner'

changeSeq(['    ', '.   ', '..  ', '... ', '....', ' ...', '  ..', '   .'])

// third-party imports
import 'colors'
import { cd, exec as cmd } from 'shelljs'
import findConfig from 'find-config'

// constants
const CONFIG = 'northbrook.json'

export const filterScopes = name => name.replace(/@[a-z]+\//g, '')

export function isInitialized (config, commandName) {
  if (!config) {
    throw new Error(`${commandName}: a northbrook.json is required for this command`)
  }
}

/**
 * Splits a semantic version number into an array of 3 parts
 */
export function splitVersion (version) {
  const _version =
    filter(map(filter(version.split('.'),
               x => x !== ''),
          x => x === 'x' || parseInt(x)),
    x => x === 'x' || !Number.isNaN(x))

  if (_version.length !== 3) {
    throw new Error(`${version} passed is not a proper semantic version number`)
  }

  return _version
}

/**
 * gets a northbrook.json configuration file
 * [options an options object for find-config]
 * @type {Object} contains 'path', 'directory', 'config' properties
 */
export function getConfig (file, options = { home: false }) {
  const path = findConfig(file || CONFIG, options)

  if (!isFile(path)) {
    return { path: null, directory: null, config: null }
  }

  const directory = dirname(path)
  const config = Object.assign({}, require(path))

  return { directory, config }
}

/**
 * tests if an absolute path exists
 */
export function exists (pathname) {
  try {
    return statSync(pathname)
  } catch (e) {
    return false
  }
}

/**
 * tests if an absolute path is a directory
 */
export function isDirectory (pathname) {
  const stats = exists(pathname)
  return stats ? stats.isDirectory() : false
}

/**
 * tests if an absolute path is a file
 */
export function isFile (pathname) {
  const stats = exists(pathname)
  return stats ? stats.isFile() : false
}

/**
 * tests if an absolute path is a symbolic link
 */
export function isLink (pathname) {
  try {
    lstatSync(pathname).isSymbolicLink()
  } catch (e) {
    return false
  }
}

/**
 * Gets all files in a directory
 */
export function getAllInDirectory (directory, recursive = false) {
  return reduce(readdirSync(directory), [], (files, file) => {
    const abspath = join(directory, file)

    if (isFile(abspath)) {
      return files.concat(file)
    }

    if (recursive && isDirectory(abspath)) {
      return files.concat(...getAllInDirectory(abspath))
    }

    return files
  })
}

const hasPkg = file => isFile(join(file, 'package.json'))
/**
 * Gets all packages from a config file to accepts wild card syntax
 */
export function resolvePackages (config, workingDir) {
  const toRelative = name => relative(workingDir, name)
  if (config && Array.isArray(config.packages)) {
    return reduce(config.packages, [], (packages, packageName) => {
      if (packageName.endsWith('**')) {
        const packageDir = join(workingDir, packageName.replace('**', ''))
        const files = map(filter(getAllInDirectory(packageDir), hasPkg), toRelative)
        return packages.concat(files)
      }
      return packages.concat(packageName)
    })
  }

  return []
}

/**
 * returns 80 character wide string used to log a separation between
 * outputs
 */
export function separator (packageName) {
  let length = typeof packageName === 'string'
    ? Math.round((76 - packageName.length) / 2)
    : 76 / 2

  if (packageName && packageName.length % 2 !== 0) {
    length = length - 1
  }

  const arr = Array(length)
  for (let i = 0; i < arr.length; ++i) {
    arr[i] = '-'
  }
  const dashes = arr.join('')

  let output = packageName && packageName.length % 2 === 0 && packageName ||
               packageName && packageName + '-' || ''

  return (`\n##` + `${dashes}`.white + `${output}` + `${dashes}`.white + `##\n`)
}

/**
 * clears the console
 */
export function clear () {
  console.log('\x1Bc')
}

/**
 * returns if something is a plugin
 */
export function isPlugin (x) {
  return x && typeof x === 'object' && typeof x.plugin === 'function'
}

/**
 * Trys to require and return a plugin
 */
export function tryRequirePlugin (path) {
  try {
    const pkg = require(path)
    return isPlugin(pkg) ? pkg : { plugin: false }
  } catch (e) {
    return { plugin: null }
  }
}

/**
 * given a path will require that object an
 */
export function pluck (args, obj) {
  function pluckReduce (a, b) {
    if (typeof a === 'string') return b[a]
    return reduce(a, b, (obj, x) => {
      if (!obj || typeof obj !== 'object') {
        return null
      }
      return obj[x]
    })
  }

  // curry this thing
  switch (arguments.length) {
    case 1: return (b) => pluckReduce(args, b)
    case 2: return pluckReduce(args, obj)
    default: return pluckReduce(args, obj)
  }
}

/**
 * filters out plugins that are to be ignored
 */
export function filterDefaultPlugins (config, defaults) {
  return config && config.ignoreDefaults && Array.isArray(config.ignoreDefaults)
    ? filter(defaults, plugin => config.ignoreDefaults.indexOf(plugin.name) === -1)
    : defaults
}

/**
 * returns all plugins as defined in a northbrook.json
 */
export function resolvePlugins (config, workingDir) {
  function getPlugin (pluginName) {
    return tryRequirePlugin(pluginName).plugin || // try normal require
           tryRequirePlugin(join(workingDir, pluginName)).plugin || // try relative require
           tryRequirePlugin(join(workingDir, 'node_modules', pluginName)).plugin || // try manual require from node_modules
           false
  }

  if (!config) return []

  const prefix = name => 'northbrook-' + name
  const scopePrefix = name => '@northbrook/' + name

  const plugins = pluck('plugins', config) && config.plugins.slice() // no mutation of original allowd

  return plugins && filter(
      map(plugins, getPlugin)
        .concat(map(map(plugins, prefix), getPlugin))
        .concat(map(map(plugins, scopePrefix), getPlugin))
      , Boolean
    ) || []
}

export function resolveExtends (config, workingDir) {
  function getExtends (extensionName) {
    return tryRequirePlugin(extensionName).config || // try normal require
           tryRequirePlugin(join(workingDir, extensionName)).config || // try relative require
           tryRequirePlugin(join(workingDir, 'node_modules', extensionName)).config || // try manual require from node_modules
           false
  }

  if (!config) return {}

  const prefix = 'northbrook-'
  const scopePrefix = '@northbrook/'

  const extension = pluck('extends', config)

  return extension &&
        getExtends(extension) ||
        getExtends(prefix + extension) ||
        getExtends(scopePrefix + extension) || {}
}

/**
 *  filters all packages to match only a specific package
 */
export function onlyPackage (name, packages) {
  return filter(packages, packagename => packagename === name)
}

export function log (progress, ...args) {
  if (progress) {
    if (typeof progress === 'string') {
      return process.stdout.write(`${[progress].concat(args || []).map(modOutput).join(' ')}\n`, { encoding: 'UTF-8' })
    } else if (progress === true) {
      process.stdout.write(`${args.map(modOutput).join(' ')}`, { encoding: 'UTF-8' })
      start()
    }
    return
  }
  process.stdout.write('\n', { encoding: 'UTF-8' })
}

/**
 *  add 4 spaces to all lines
 */
export function modOutput (output) {
  return output.replace('\n', '\n    ').replace('\r', '\r    ')
}

/**
 *  change the current directory
 */
export function chdir (path) {
  cd(path)
}

/**
 * executes a command asynchronously
 */
export function exec (command, options = { silent: true }) {
  return new Promise((resolve, reject) => {
    cmd(command, options, function (code, out, err) {
      resolve({ cmd: command, code, out, err })
    })
  })
}

// user-land array functions for perf
// tested by testing all of the above functions

export function forEach (arr, fn) {
  const l = arr.length
  for (let i = 0; i < l; ++i) {
    fn(arr[i], i)
  }
}

export function map (arr, fn) {
  const newArr = []
  forEach(arr, (x, i) => { newArr[i] = fn(x, i) })
  return newArr
}

export function reduce (arr, seed, fn) {
  let r = seed

  forEach(arr, (x) => {
    r = fn(r, x)
  })

  return r
}

export function filter (arr, predicate) {
  const newArr = []

  forEach(arr, (x, i) => {
    if (predicate(x, i)) {
      newArr[newArr.length] = x
    }
  })

  return newArr
}
<commit_msg>fix(northbrook): use working directory when no packages are defined<commit_after>// node.js imports
import { join, dirname, relative } from 'path'
import { statSync, lstatSync, readdirSync } from 'fs'
import { start, change_sequence as changeSeq } from 'simple-spinner'

changeSeq(['    ', '.   ', '..  ', '... ', '....', ' ...', '  ..', '   .'])

// third-party imports
import 'colors'
import { cd, exec as cmd } from 'shelljs'
import findConfig from 'find-config'

// constants
const CONFIG = 'northbrook.json'

export const filterScopes = name => name.replace(/@[a-z]+\//g, '')

export function isInitialized (config, commandName) {
  if (!config) {
    throw new Error(`${commandName}: a northbrook.json is required for this command`)
  }
}

/**
 * Splits a semantic version number into an array of 3 parts
 */
export function splitVersion (version) {
  const _version =
    filter(map(filter(version.split('.'),
               x => x !== ''),
          x => x === 'x' || parseInt(x)),
    x => x === 'x' || !Number.isNaN(x))

  if (_version.length !== 3) {
    throw new Error(`${version} passed is not a proper semantic version number`)
  }

  return _version
}

/**
 * gets a northbrook.json configuration file
 * [options an options object for find-config]
 * @type {Object} contains 'path', 'directory', 'config' properties
 */
export function getConfig (file, options = { home: false }) {
  const path = findConfig(file || CONFIG, options)

  if (!isFile(path)) {
    return { path: null, directory: null, config: null }
  }

  const directory = dirname(path)
  const config = Object.assign({}, require(path))

  return { directory, config }
}

/**
 * tests if an absolute path exists
 */
export function exists (pathname) {
  try {
    return statSync(pathname)
  } catch (e) {
    return false
  }
}

/**
 * tests if an absolute path is a directory
 */
export function isDirectory (pathname) {
  const stats = exists(pathname)
  return stats ? stats.isDirectory() : false
}

/**
 * tests if an absolute path is a file
 */
export function isFile (pathname) {
  const stats = exists(pathname)
  return stats ? stats.isFile() : false
}

/**
 * tests if an absolute path is a symbolic link
 */
export function isLink (pathname) {
  try {
    lstatSync(pathname).isSymbolicLink()
  } catch (e) {
    return false
  }
}

/**
 * Gets all files in a directory
 */
export function getAllInDirectory (directory, recursive = false) {
  return reduce(readdirSync(directory), [], (files, file) => {
    const abspath = join(directory, file)

    if (isFile(abspath)) {
      return files.concat(file)
    }

    if (recursive && isDirectory(abspath)) {
      return files.concat(...getAllInDirectory(abspath))
    }

    return files
  })
}

const hasPkg = file => isFile(join(file, 'package.json'))
/**
 * Gets all packages from a config file to accepts wild card syntax
 */
export function resolvePackages (config, workingDir) {
  const toRelative = name => relative(workingDir, name)
  if (config) {
    if (Array.isArray(config.packages)) {
      if (config.packages.length === 0) {
        return ['.']
      }
      return reduce(config.packages, [], (packages, packageName) => {
        if (packageName.endsWith('**')) {
          const packageDir = join(workingDir, packageName.replace('**', ''))
          const files = map(filter(getAllInDirectory(packageDir), hasPkg), toRelative)
          return packages.concat(files)
        }
        return packages.concat(packageName)
      })
    } else {
      return ['.']
    }
  }

  return []
}

/**
 * returns 80 character wide string used to log a separation between
 * outputs
 */
export function separator (packageName) {
  let length = typeof packageName === 'string'
    ? Math.round((76 - packageName.length) / 2)
    : 76 / 2

  if (packageName && packageName.length % 2 !== 0) {
    length = length - 1
  }

  const arr = Array(length)
  for (let i = 0; i < arr.length; ++i) {
    arr[i] = '-'
  }
  const dashes = arr.join('')

  let output = packageName && packageName.length % 2 === 0 && packageName ||
               packageName && packageName + '-' || ''

  return (`\n##` + `${dashes}`.white + `${output}` + `${dashes}`.white + `##\n`)
}

/**
 * clears the console
 */
export function clear () {
  console.log('\x1Bc')
}

/**
 * returns if something is a plugin
 */
export function isPlugin (x) {
  return x && typeof x === 'object' && typeof x.plugin === 'function'
}

/**
 * Trys to require and return a plugin
 */
export function tryRequirePlugin (path) {
  try {
    const pkg = require(path)
    return isPlugin(pkg) ? pkg : { plugin: false }
  } catch (e) {
    return { plugin: null }
  }
}

/**
 * given a path will require that object an
 */
export function pluck (args, obj) {
  function pluckReduce (a, b) {
    if (typeof a === 'string') return b[a]
    return reduce(a, b, (obj, x) => {
      if (!obj || typeof obj !== 'object') {
        return null
      }
      return obj[x]
    })
  }

  // curry this thing
  switch (arguments.length) {
    case 1: return (b) => pluckReduce(args, b)
    case 2: return pluckReduce(args, obj)
    default: return pluckReduce(args, obj)
  }
}

/**
 * filters out plugins that are to be ignored
 */
export function filterDefaultPlugins (config, defaults) {
  return config && config.ignoreDefaults && Array.isArray(config.ignoreDefaults)
    ? filter(defaults, plugin => config.ignoreDefaults.indexOf(plugin.name) === -1)
    : defaults
}

/**
 * returns all plugins as defined in a northbrook.json
 */
export function resolvePlugins (config, workingDir) {
  function getPlugin (pluginName) {
    return tryRequirePlugin(pluginName).plugin || // try normal require
           tryRequirePlugin(join(workingDir, pluginName)).plugin || // try relative require
           tryRequirePlugin(join(workingDir, 'node_modules', pluginName)).plugin || // try manual require from node_modules
           false
  }

  if (!config) return []

  const prefix = name => 'northbrook-' + name
  const scopePrefix = name => '@northbrook/' + name

  const plugins = pluck('plugins', config) && config.plugins.slice() // no mutation of original allowd

  return plugins && filter(
      map(plugins, getPlugin)
        .concat(map(map(plugins, prefix), getPlugin))
        .concat(map(map(plugins, scopePrefix), getPlugin))
      , Boolean
    ) || []
}

export function resolveExtends (config, workingDir) {
  function getExtends (extensionName) {
    return tryRequirePlugin(extensionName).config || // try normal require
           tryRequirePlugin(join(workingDir, extensionName)).config || // try relative require
           tryRequirePlugin(join(workingDir, 'node_modules', extensionName)).config || // try manual require from node_modules
           false
  }

  if (!config) return {}

  const prefix = 'northbrook-'
  const scopePrefix = '@northbrook/'

  const extension = pluck('extends', config)

  return extension &&
        getExtends(extension) ||
        getExtends(prefix + extension) ||
        getExtends(scopePrefix + extension) || {}
}

/**
 *  filters all packages to match only a specific package
 */
export function onlyPackage (name, packages) {
  return filter(packages, packagename => packagename === name)
}

export function log (progress, ...args) {
  if (progress) {
    if (typeof progress === 'string') {
      return process.stdout.write(`${[progress].concat(args || []).map(modOutput).join(' ')}\n`, { encoding: 'UTF-8' })
    } else if (progress === true) {
      process.stdout.write(`${args.map(modOutput).join(' ')}`, { encoding: 'UTF-8' })
      start()
    }
    return
  }
  process.stdout.write('\n', { encoding: 'UTF-8' })
}

/**
 *  add 4 spaces to all lines
 */
export function modOutput (output) {
  return output.replace('\n', '\n    ').replace('\r', '\r    ')
}

/**
 *  change the current directory
 */
export function chdir (path) {
  cd(path)
}

/**
 * executes a command asynchronously
 */
export function exec (command, options = { silent: true }) {
  return new Promise((resolve, reject) => {
    cmd(command, options, function (code, out, err) {
      resolve({ cmd: command, code, out, err })
    })
  })
}

// user-land array functions for perf
// tested by testing all of the above functions

export function forEach (arr, fn) {
  const l = arr.length
  for (let i = 0; i < l; ++i) {
    fn(arr[i], i)
  }
}

export function map (arr, fn) {
  const newArr = []
  forEach(arr, (x, i) => { newArr[i] = fn(x, i) })
  return newArr
}

export function reduce (arr, seed, fn) {
  let r = seed

  forEach(arr, (x) => {
    r = fn(r, x)
  })

  return r
}

export function filter (arr, predicate) {
  const newArr = []

  forEach(arr, (x, i) => {
    if (predicate(x, i)) {
      newArr[newArr.length] = x
    }
  })

  return newArr
}
<|endoftext|>


<commit_before>//main.js
/*var flights = [[{dest: "Poland", price: "242", carrier: "Ryan Air"},
                    {dest: "Poland", price: "60", carrier: "British Airways"},
                    {dest: "Poland", price: "260", carrier: "Joe's Hardware"}],
            [ {dest: "Bristol", price: "160", carrier: "British Airways"},
                    {dest: "Bristol", price: "20", carrier: "Joe's Hardware"}]];
*/
var flights;
var ready = false;
//get flight data
$.get( "/top_flights", function( data ) {
    flights = JSON.parse(data);
    populate_data();
});
$(document).ready( function () {

    $('#chooser a').click(function (e) {
	e.preventDefault();
	$(this).tab('show');
    if(!$("#tab-main").hasClass("active")){ $("#tab-main").removeClass("hide");}
        else { $("#tab-main").addClass("hide"); }
    if(!$("#tab-friends").hasClass("active")){ $("#tab-friends").removeClass("hide");}
        else { $("#tab-friends").addClass("hide"); }
    });

    $(".btn-modal").on("click", function () {
        //set modal to loading!
        if(ready) {
            reset_modal();
            $('#myModal').modal('toggle');
            //populate the modal here!!!
            populate_modal($(this).attr("location"));
        }
    });

    $(".friendlist tr").on("click", function() {
        var any_selected = false;
        var q = $(this).children(":last").children(".friend-location").text();
        $(".friend-location").each(function () {
            if($(this).hasClass("selected")) {any_selected = true; }
            if($(this).text().toLowerCase().indexOf(q.toLowerCase()) != -1) {
                $(this).parent().parent().show();
            } else {
                $(this).parent().parent().hide();
            }
        });
        $(this).toggleClass("selected");
        if(!any_selected) {
            $(".friend-location").each(function () {
                $(this).parent().parent().show();
            });
        }
    });
    $('#search').on("keyup", function () {
        var q = $('#search').val();
        $(".friend-name").each(function () {
            if ($(this).text().toLowerCase().indexOf(q.toLowerCase()) != -1) {
                $(this).parent().parent().show();
            }
            else {
                $(this).parent().parent().hide();
            }
        });
    });
});
function reset_modal() {
    //resets the modal to a loading screen
    $("#modalTitle").text("Loading...");
    $("#flight-data tr").remove();
    $("#flight-data").html("
Date	Agent	Fly Now!
");
}
function populate_modal(city_id) {
    //this gets all relevant data for the modal
    var data = flights[city_id];
    $("#modalTitle").text(data.name[0]+", "+data.name[1]+", "+data.name[2]);
    $("#skyscanner-url").attr('href', flights[city_id]['url']);
    $("#flight-data tr:last").after(prepare_flight(data.cheapest_quote));
    data.quotes.forEach(function (entry) {
        $("#flight-data tr:last").after(prepare_flight(entry));
    });
    $(".date-tooltip").tooltip();
}
function populate_data() {
    ready = true;
    $("#Loading-Content").addClass("hidden");
    $("#first-location h1").html(flights[0].name[1] + "
£"+flights[0].cheapest_quote.MinPrice);
    $("#first-location p").html("Go and see "+flights[0].friends[0].name+", "+flights[0].friends[1].name+" and "+(flights[0].friends.length - 2)+" others in "+flights[0].name[1]+", "+flights[0].name[2]);
    $("#first-location button").attr("location", 0);
    $("#first-location").removeClass("hidden");
    $("#second-location h1").html(flights[1].name[1] + "
£"+flights[1].cheapest_quote.MinPrice);
    $("#second-location p").html("You have "+flights[1].friends.length+" friends near "+flights[1].name[1]+", including "+flights[1].friends[0].name+"");
    $("#second-location button").attr("location", 1);
    $("#second-location").removeClass("hidden");
    $("#third-location h1").html(flights[2].name[1] + "
£"+flights[2].cheapest_quote.MinPrice);
    $("#third-location p").html("Flights available to go and see "+flights[2].friends[0].name+" and "+(flights[2].friends.length -1)+" others in "+flights[2].name[1]);
    $("#third-location button").attr("location", 2);
    $("#third-location").removeClass("hidden");
}
function prepare_flight(dest) {
    var date = moment(dest.InboundLeg.DepartureDate).format('ll');
    var rel_date = moment(dest.InboundLeg.DepartureDate).fromNow();
    //add a 'time until' event using .fromNow() as a tooltip
    var r = "
";
    r += "

"+date+"	";
    r += ""+dest.InboundLeg.Carrier+"	";
    r += "£"+dest.MinPrice+"	";
    r += "
";
    return r;
}
<commit_msg>random text<commit_after>//main.js
/*var flights = [[{dest: "Poland", price: "242", carrier: "Ryan Air"},
                    {dest: "Poland", price: "60", carrier: "British Airways"},
                    {dest: "Poland", price: "260", carrier: "Joe's Hardware"}],
            [ {dest: "Bristol", price: "160", carrier: "British Airways"},
                    {dest: "Bristol", price: "20", carrier: "Joe's Hardware"}]];
*/
var flights;
var ready = false;
//get flight data
$.get( "/top_flights", function( data ) {
    flights = JSON.parse(data);
    populate_data();
});
$(document).ready( function () {

    $('#chooser a').click(function (e) {
	e.preventDefault();
	$(this).tab('show');
    if(!$("#tab-main").hasClass("active")){ $("#tab-main").removeClass("hide");}
        else { $("#tab-main").addClass("hide"); }
    if(!$("#tab-friends").hasClass("active")){ $("#tab-friends").removeClass("hide");}
        else { $("#tab-friends").addClass("hide"); }
    });

    $(".btn-modal").on("click", function () {
        //set modal to loading!
        if(ready) {
            reset_modal();
            $('#myModal').modal('toggle');
            //populate the modal here!!!
            populate_modal($(this).attr("location"));
        }
    });

    $(".friendlist tr").on("click", function() {
        var any_selected = false;
        var q = $(this).children(":last").children(".friend-location").text();
        $(".friend-location").each(function () {
            if($(this).hasClass("selected")) {any_selected = true; }
            if($(this).text().toLowerCase().indexOf(q.toLowerCase()) != -1) {
                $(this).parent().parent().show();
            } else {
                $(this).parent().parent().hide();
            }
        });
        $(this).toggleClass("selected");
        }
    });
    $('#search').on("keyup", function () {
        var q = $('#search').val();
        $(".friend-name").each(function () {
            if ($(this).text().toLowerCase().indexOf(q.toLowerCase()) != -1) {
                $(this).parent().parent().show();
            }
            else {
                $(this).parent().parent().hide();
            }
        });
    });
});
function reset_modal() {
    //resets the modal to a loading screen
    $("#modalTitle").text("Loading...");
    $("#flight-data tr").remove();
    $("#flight-data").html("
Date	Agent	Fly Now!
");
}
function populate_modal(city_id) {
    //this gets all relevant data for the modal
    var data = flights[city_id];
    $("#modalTitle").text(data.name[0]+", "+data.name[1]+", "+data.name[2]);
    $("#skyscanner-url").attr('href', flights[city_id]['url']);
    $("#flight-data tr:last").after(prepare_flight(data.cheapest_quote));
    data.quotes.forEach(function (entry) {
        $("#flight-data tr:last").after(prepare_flight(entry));
    });
    $(".date-tooltip").tooltip();
}
function populate_data() {
    ready = true;
    $("#Loading-Content").addClass("hidden");
    $("#first-location h1").html(flights[0].name[1] + "
£"+flights[0].cheapest_quote.MinPrice);
    $("#first-location p").html("Go and see "+flights[0].friends[0].name+", "+flights[0].friends[1].name+" and "+(flights[0].friends.length - 2)+" others in "+flights[0].name[1]+", "+flights[0].name[2]);
    $("#first-location button").attr("location", 0);
    $("#first-location").removeClass("hidden");
    $("#second-location h1").html(flights[1].name[1] + "
£"+flights[1].cheapest_quote.MinPrice);
    $("#second-location p").html("You have "+flights[1].friends.length+" friends near "+flights[1].name[1]+", including "+flights[1].friends[0].name+"");
    $("#second-location button").attr("location", 1);
    $("#second-location").removeClass("hidden");
    $("#third-location h1").html(flights[2].name[1] + "
£"+flights[2].cheapest_quote.MinPrice);
    $("#third-location p").html("Flights available to go and see "+flights[2].friends[0].name+" and "+(flights[2].friends.length -1)+" others in "+flights[2].name[1]);
    $("#third-location button").attr("location", 2);
    $("#third-location").removeClass("hidden");
}
function prepare_flight(dest) {
    var date = moment(dest.InboundLeg.DepartureDate).format('ll');
    var rel_date = moment(dest.InboundLeg.DepartureDate).fromNow();
    //add a 'time until' event using .fromNow() as a tooltip
    var r = "
";
    r += "

"+date+"	";
    r += ""+dest.InboundLeg.Carrier+"	";
    r += "£"+dest.MinPrice+"	";
    r += "
";
    return r;
}
<|endoftext|>


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

  angular
    .module('app')
    .controller('SedBeddingTabController', SedBeddingTabController);

  SedBeddingTabController.$inject = ['$ionicModal', '$ionicPopup', '$log', '$scope', '$state', 'FormFactory'];

  function SedBeddingTabController($ionicModal, $ionicPopup, $log, $scope, $state, FormFactory) {
    var vm = this;
    var vmParent = $scope.vm;

    var thisTabName = 'sed-bedding';

    vm.shouldShowInterbedBeddingFields = shouldShowInterbedBeddingFields;
    vm.shouldShowPackageBeddingFields = shouldShowPackageBeddingFields;

    activate();

    /**
     * Private Functions
     */

    function activate() {
      $log.log('In SedBeddingTabController');

      // Loading tab from Spots list
      if ($state.current.name === 'app.spotTab.' + thisTabName) loadTab($state);
      // Loading tab in Map side panel
      $scope.$on('load-tab', function (event, args) {
        if (args.tabName === thisTabName) {
          vmParent.saveSpot().finally(function () {
            vmParent.spotChanged = false;
            loadTab({
              'current': {'name': 'app.spotTab.' + thisTabName},
              'params': {'spotId': args.spotId}
            });
          });
        }
      });
    }

    function loadTab(state) {
      vmParent.loadTab(state);     // Need to load current state into parent
      if (vmParent.spot && !_.isEmpty(vmParent.spot)) {
        FormFactory.setForm('sed', 'bedding');

        vmParent.data = {};
        if (vmParent.spot.properties.sed && vmParent.spot.properties.sed.bedding){
          vmParent.dataOutsideForm = angular.copy(vmParent.spot.properties.sed.bedding);
          if (vmParent.dataOutsideForm.beds) delete vmParent.dataOutsideForm.beds;
          if (vmParent.spot.properties.sed.bedding.beds && vmParent.spot.properties.sed.bedding.beds[vmParent.lithologyNum]) {
            vmParent.data = angular.copy(vmParent.spot.properties.sed.bedding.beds[vmParent.lithologyNum]);
          }
        }
        $log.log('Sed Bedding Shared :', vmParent.dataOutsideForm);
        $log.log('Sed Bedding Lithology ' + (vmParent.lithologyNum + 1) + ':', vmParent.data);
      }
    }

    /**
     * Public Functions
     */

    function shouldShowInterbedBeddingFields() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.sed && vmParent.spot.properties.sed.character &&
        (vmParent.spot.properties.sed.character === 'interbedded' || vmParent.spot.properties.sed.character === 'bed_mixed_lit');
    }

    function shouldShowPackageBeddingFields() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.sed && vmParent.spot.properties.sed.character &&
        vmParent.spot.properties.sed.character === 'package_succe';
    }
  }
}());
<commit_msg>Sed Beddding: Handle change of interval proportion change field<commit_after>(function () {
  'use strict';

  angular
    .module('app')
    .controller('SedBeddingTabController', SedBeddingTabController);

  SedBeddingTabController.$inject = ['$ionicModal', '$ionicPopup', '$log', '$scope', '$state', 'FormFactory'];

  function SedBeddingTabController($ionicModal, $ionicPopup, $log, $scope, $state, FormFactory) {
    var vm = this;
    var vmParent = $scope.vm;

    var thisTabName = 'sed-bedding';

    vm.shouldShowInterbedBeddingFields = shouldShowInterbedBeddingFields;
    vm.shouldShowPackageBeddingFields = shouldShowPackageBeddingFields;

    activate();

    /**
     * Private Functions
     */

    function activate() {
      $log.log('In SedBeddingTabController');

      // Loading tab from Spots list
      if ($state.current.name === 'app.spotTab.' + thisTabName) loadTab($state);
      // Loading tab in Map side panel
      $scope.$on('load-tab', function (event, args) {
        if (args.tabName === thisTabName) {
          vmParent.saveSpot().finally(function () {
            vmParent.spotChanged = false;
            loadTab({
              'current': {'name': 'app.spotTab.' + thisTabName},
              'params': {'spotId': args.spotId}
            });
          });
        }
      });
    }

    function loadTab(state) {
      vmParent.loadTab(state);     // Need to load current state into parent
      if (vmParent.spot && !_.isEmpty(vmParent.spot)) {
        FormFactory.setForm('sed', 'bedding');

        vmParent.data = {};
        if (vmParent.spot.properties.sed && vmParent.spot.properties.sed.bedding) {
          vmParent.dataOutsideForm = angular.copy(vmParent.spot.properties.sed.bedding);
          if (vmParent.spot.properties.sed.bedding.beds && vmParent.spot.properties.sed.bedding.beds[vmParent.lithologyNum]) {
            vmParent.data = angular.copy(vmParent.spot.properties.sed.bedding.beds[vmParent.lithologyNum]);
          }
        }
        $log.log('Sed Bedding Shared :', vmParent.dataOutsideForm);
        $log.log('Sed Bedding Lithology ' + (vmParent.lithologyNum + 1) + ':', vmParent.data);
      }
      createWatches();
    }

    function createWatches() {
      // Watch for interbed_proportion_change changes
      $scope.$watch('vm.dataOutsideForm.interbed_proportion_change', function (newValue, oldValue) {
        if (newValue && newValue !== oldValue) checkInterbedProportionChangeField();
      });
    }

    function checkInterbedProportionChangeField() {
      var avgThicknessEl = document.getElementById('avg_thickness');
      var minThicknessEl = document.getElementById('min_thickness');
      var maxThicknessEl = document.getElementById('max_thickness');
      if (avgThicknessEl) {
        if (vmParent.dataOutsideForm.interbed_proportion_change === 'increase'
          || vmParent.dataOutsideForm.interbed_proportion_change === 'decrease') {
          avgThicknessEl.style.display = 'none';
          minThicknessEl.style.display = '';
          maxThicknessEl.style.display = '';
          // Delete avg thickness fields
          if (vmParent.data.avg_thickness) delete vmParent.data.avg_thickness;
          if (vmParent.spot.properties && vmParent.spot.properties.sed) {
            var sed = vmParent.spot.properties.sed;
            _.times(2, function (n) {
              if (sed.bedding && sed.bedding.beds && sed.bedding.beds[n]) {
                if (sed.bedding.beds[n].avg_thickness) delete sed.bedding.beds[n].avg_thickness;
              }
            });
          }
        }
        else if (vmParent.dataOutsideForm.interbed_proportion_change === 'no_change') {
          avgThicknessEl.style.display = '';
          minThicknessEl.style.display = 'none';
          maxThicknessEl.style.display = 'none';
          // Delete any min & max thickness fields
          if (vmParent.data.max_thickness) delete vmParent.data.max_thickness;
          if (vmParent.data.min_thickness) delete vmParent.data.min_thickness;
          if (vmParent.spot.properties && vmParent.spot.properties.sed) {
            var sed = vmParent.spot.properties.sed;
            _.times(2, function (n) {
              if (sed.bedding && sed.bedding.beds && sed.bedding.beds[n]) {
                if (sed.bedding.beds[n].min_thickness) delete sed.bedding.beds[n].min_thickness;
                if (sed.bedding.beds[n].max_thickness) delete sed.bedding.beds[n].max_thickness;
              }
            });
          }
        }
      }
    }

    /**
     * Public Functions
     */

    function shouldShowInterbedBeddingFields() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.sed && vmParent.spot.properties.sed.character &&
        (vmParent.spot.properties.sed.character === 'interbedded' || vmParent.spot.properties.sed.character === 'bed_mixed_lit');
    }

    function shouldShowPackageBeddingFields() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.sed && vmParent.spot.properties.sed.character &&
        vmParent.spot.properties.sed.character === 'package_succe';
    }
  }
}());
<|endoftext|>