<commit_before>/**
 * File System Access
 * Draft Community Group Report, 18 November 2020
 * @externs
 * @see https://wicg.github.io/file-system-access/
 */

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemhandlepermissiondescriptor
 */
var FileSystemHandlePermissionDescriptor = function() {};

/** @type {undefined|string} */
FileSystemHandlePermissionDescriptor.prototype.mode;

/**
 * @typedef {string}
 * @see https://wicg.github.io/file-system-access/#enumdef-filesystemhandlekind
 */
var FileSystemHandleKind;

/**
 * @interface
 * @see https://wicg.github.io/file-system-access/#api-filesystemhandle
 */
var FileSystemHandle = function() {};

/** @type {!FileSystemHandleKind} @const */
FileSystemHandle.prototype.kind;

/** @type {string} @const */
FileSystemHandle.prototype.name;

/**
 * @param {!FileSystemHandle} other
 * @return {!Promise<boolean>}
 */
FileSystemHandle.prototype.isSameEntry = function(other) {};

/**
 * @param {!FileSystemHandlePermissionDescriptor=} opt_descriptor
 * @return {!Promise<!PermissionState>}
 */
FileSystemHandle.prototype.queryPermission = function(opt_descriptor) {};

/**
 * @param {!FileSystemHandlePermissionDescriptor=} opt_descriptor
 * @return {!Promise<!PermissionState>}
 */
FileSystemHandle.prototype.requestPermission = function(opt_descriptor) {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemcreatewritableoptions
 */
var FileSystemCreateWritableOptions = function() {};

/** @type {undefined|boolean} */
FileSystemCreateWritableOptions.prototype.keepExistingData;

/**
 * @interface
 * @extends {FileSystemHandle}
 * @see https://wicg.github.io/file-system-access/#api-filesystemfilehandle
 */
var FileSystemFileHandle = function() {};

/**
 * @return {!Promise<!File>}
 */
FileSystemFileHandle.prototype.getFile = function() {};

/**
 * @param {!FileSystemCreateWritableOptions=} opt_options
 * @return {!Promise<!FileSystemWritableFileStream>}
 */
FileSystemFileHandle.prototype.createWritable = function(opt_options) {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemgetfileoptions
 */
var FileSystemGetFileOptions = function() {};

/** @type {undefined|boolean} */
FileSystemGetFileOptions.prototype.create;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemgetdirectoryoptions
 */
var FileSystemGetDirectoryOptions = function() {};

/** @type {undefined|boolean} */
FileSystemGetDirectoryOptions.prototype.create;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemremoveoptions
 */
var FileSystemRemoveOptions = function() {};

/** @type {undefined|boolean} */
FileSystemRemoveOptions.prototype.recursive;

/**
 * @interface
 * @extends {FileSystemHandle}
 * @extends {AsyncIterable<string, !FileSystemHandle>}
 * @see https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle
 */
var FileSystemDirectoryHandle = function() {};

/**
 * @param {string} name
 * @param {!FileSystemGetFileOptions=} opt_options
 * @return {!Promise<!FileSystemFileHandle>}
 */
FileSystemDirectoryHandle.prototype.getFileHandle = function(name, opt_options) {};

/**
 * @param {string} name
 * @param {!FileSystemGetDirectoryOptions=} opt_options
 * @return {!Promise<!FileSystemDirectoryHandle>}
 */
FileSystemDirectoryHandle.prototype.getDirectoryHandle = function(name, opt_options) {};

/**
 * @param {string} name
 * @param {!FileSystemRemoveOptions=} opt_options
 * @return {!Promise<void>}
 */
FileSystemDirectoryHandle.prototype.removeEntry = function(name, opt_options) {};

/**
 * @param {!FileSystemHandle} possibleDescendant
 * @return {!Promise<?Array<string>>}
 */
FileSystemDirectoryHandle.prototype.resolve = function(possibleDescendant) {};

/**
 * @typedef {string}
 * @see https://wicg.github.io/file-system-access/#enumdef-writecommandtype
 */
var WriteCommandType;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-writeparams
 */
var WriteParams = function() {};

/** @type {!WriteCommandType} */
WriteParams.prototype.type;

/** @type {undefined|?number} */
WriteParams.prototype.size;

/** @type {undefined|?number} */
WriteParams.prototype.position;

/** @type {undefined|!BufferSource|!Blob|?string} */
WriteParams.prototype.data;

/**
 * @typedef {!BufferSource|!Blob|string|!WriteParams}
 * @see https://wicg.github.io/file-system-access/#typedefdef-filesystemwritechunktype
 */
var FileSystemWriteChunkType;

/**
 * @constructor
 * @extends {WritableStream}
 * @see https://wicg.github.io/file-system-access/#filesystemwritablefilestream
 */
var FileSystemWritableFileStream = function() {};

/**
 * @param {!FileSystemWriteChunkType} data
 * @return {!Promise<void>}
 */
FileSystemWritableFileStream.prototype.write = function(data) {};

/**
 * @param {number} position
 * @return {!Promise<void>}
 */
FileSystemWritableFileStream.prototype.seek = function(position) {};

/**
 * @param {number} size
 * @return {!Promise<void>}
 */
FileSystemWritableFileStream.prototype.truncate = function(size) {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filepickeraccepttype
 */
var FilePickerAcceptType = function() {};

/** @type {undefined|string} */
FilePickerAcceptType.prototype.description;

/** @type {undefined|!Object<string,(string|!Array<string>)>} */
FilePickerAcceptType.prototype.accept;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filepickeroptions
 */
var FilePickerOptions = function() {};

/** @type {undefined|!Array<!FilePickerAcceptType>} */
FilePickerOptions.prototype.types;

/** @type {undefined|boolean} */
FilePickerOptions.prototype.excludeAcceptAllOption;

/**
 * @record
 * @struct
 * @extends {FilePickerOptions}
 * @see https://wicg.github.io/file-system-access/#dictdef-openfilepickeroptions
 */
var OpenFilePickerOptions = function() {};

/** @type {undefined|boolean} */
OpenFilePickerOptions.prototype.multiple;

/**
 * @record
 * @struct
 * @extends {FilePickerOptions}
 * @see https://wicg.github.io/file-system-access/#dictdef-savefilepickeroptions
 */
var SaveFilePickerOptions = function() {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-directorypickeroptions
 */
var DirectoryPickerOptions = function() {};

/**
 * @param {!OpenFilePickerOptions=} opt_options
 * @return {!Promise<!Array<!FileSystemFileHandle>>}
 * @see https://wicg.github.io/file-system-access/#local-filesystem
 */
Window.prototype.showOpenFilePicker = function(opt_options) {};

/**
 * @param {!SaveFilePickerOptions=} opt_options
 * @return {!Promise<!FileSystemFileHandle>}
 * @see https://wicg.github.io/file-system-access/#local-filesystem
 */
Window.prototype.showSaveFilePicker = function(opt_options) {};

/**
 * @param {!DirectoryPickerOptions=} opt_options
 * @return {!Promise<!FileSystemDirectoryHandle>}
 * @see https://wicg.github.io/file-system-access/#local-filesystem
 */
Window.prototype.showDirectoryPicker = function(opt_options) {};
<commit_msg>Directory iterator fix<commit_after>/**
 * File System Access
 * Draft Community Group Report, 18 November 2020
 * @externs
 * @see https://wicg.github.io/file-system-access/
 */

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemhandlepermissiondescriptor
 */
var FileSystemHandlePermissionDescriptor = function() {};

/** @type {undefined|string} */
FileSystemHandlePermissionDescriptor.prototype.mode;

/**
 * @typedef {string}
 * @see https://wicg.github.io/file-system-access/#enumdef-filesystemhandlekind
 */
var FileSystemHandleKind;

/**
 * @interface
 * @see https://wicg.github.io/file-system-access/#api-filesystemhandle
 */
var FileSystemHandle = function() {};

/** @type {!FileSystemHandleKind} @const */
FileSystemHandle.prototype.kind;

/** @type {string} @const */
FileSystemHandle.prototype.name;

/**
 * @param {!FileSystemHandle} other
 * @return {!Promise<boolean>}
 */
FileSystemHandle.prototype.isSameEntry = function(other) {};

/**
 * @param {!FileSystemHandlePermissionDescriptor=} opt_descriptor
 * @return {!Promise<!PermissionState>}
 */
FileSystemHandle.prototype.queryPermission = function(opt_descriptor) {};

/**
 * @param {!FileSystemHandlePermissionDescriptor=} opt_descriptor
 * @return {!Promise<!PermissionState>}
 */
FileSystemHandle.prototype.requestPermission = function(opt_descriptor) {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemcreatewritableoptions
 */
var FileSystemCreateWritableOptions = function() {};

/** @type {undefined|boolean} */
FileSystemCreateWritableOptions.prototype.keepExistingData;

/**
 * @interface
 * @extends {FileSystemHandle}
 * @see https://wicg.github.io/file-system-access/#api-filesystemfilehandle
 */
var FileSystemFileHandle = function() {};

/**
 * @return {!Promise<!File>}
 */
FileSystemFileHandle.prototype.getFile = function() {};

/**
 * @param {!FileSystemCreateWritableOptions=} opt_options
 * @return {!Promise<!FileSystemWritableFileStream>}
 */
FileSystemFileHandle.prototype.createWritable = function(opt_options) {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemgetfileoptions
 */
var FileSystemGetFileOptions = function() {};

/** @type {undefined|boolean} */
FileSystemGetFileOptions.prototype.create;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemgetdirectoryoptions
 */
var FileSystemGetDirectoryOptions = function() {};

/** @type {undefined|boolean} */
FileSystemGetDirectoryOptions.prototype.create;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filesystemremoveoptions
 */
var FileSystemRemoveOptions = function() {};

/** @type {undefined|boolean} */
FileSystemRemoveOptions.prototype.recursive;

/**
 * @interface
 * @extends {FileSystemHandle}
 * @extends {AsyncIterable<!Array<string|!FileSystemHandle>>}
 * @see https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle
 * @see https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle-asynciterable
 */
var FileSystemDirectoryHandle = function() {};

/**
 * @param {string} name
 * @param {!FileSystemGetFileOptions=} opt_options
 * @return {!Promise<!FileSystemFileHandle>}
 */
FileSystemDirectoryHandle.prototype.getFileHandle = function(name, opt_options) {};

/**
 * @param {string} name
 * @param {!FileSystemGetDirectoryOptions=} opt_options
 * @return {!Promise<!FileSystemDirectoryHandle>}
 */
FileSystemDirectoryHandle.prototype.getDirectoryHandle = function(name, opt_options) {};

/**
 * @param {string} name
 * @param {!FileSystemRemoveOptions=} opt_options
 * @return {!Promise<void>}
 */
FileSystemDirectoryHandle.prototype.removeEntry = function(name, opt_options) {};

/**
 * @param {!FileSystemHandle} possibleDescendant
 * @return {!Promise<?Array<string>>}
 */
FileSystemDirectoryHandle.prototype.resolve = function(possibleDescendant) {};

/**
 * @return {!AsyncIterable<!Array<string|!FileSystemHandle>>}
 * @see https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle-asynciterable
 */
FileSystemDirectoryHandle.prototype.entries = function() {};

/**
 * @return {!AsyncIterable<!FileSystemHandle>}
 * @see https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle-asynciterable
 */
FileSystemDirectoryHandle.prototype.values = function() {};

/**
 * @return {!AsyncIterable<string>}
 * @see https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle-asynciterable
 */
FileSystemDirectoryHandle.prototype.keys = function() {};

/**
 * @typedef {string}
 * @see https://wicg.github.io/file-system-access/#enumdef-writecommandtype
 */
var WriteCommandType;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-writeparams
 */
var WriteParams = function() {};

/** @type {!WriteCommandType} */
WriteParams.prototype.type;

/** @type {undefined|?number} */
WriteParams.prototype.size;

/** @type {undefined|?number} */
WriteParams.prototype.position;

/** @type {undefined|!BufferSource|!Blob|?string} */
WriteParams.prototype.data;

/**
 * @typedef {!BufferSource|!Blob|string|!WriteParams}
 * @see https://wicg.github.io/file-system-access/#typedefdef-filesystemwritechunktype
 */
var FileSystemWriteChunkType;

/**
 * @constructor
 * @extends {WritableStream}
 * @see https://wicg.github.io/file-system-access/#filesystemwritablefilestream
 */
var FileSystemWritableFileStream = function() {};

/**
 * @param {!FileSystemWriteChunkType} data
 * @return {!Promise<void>}
 */
FileSystemWritableFileStream.prototype.write = function(data) {};

/**
 * @param {number} position
 * @return {!Promise<void>}
 */
FileSystemWritableFileStream.prototype.seek = function(position) {};

/**
 * @param {number} size
 * @return {!Promise<void>}
 */
FileSystemWritableFileStream.prototype.truncate = function(size) {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filepickeraccepttype
 */
var FilePickerAcceptType = function() {};

/** @type {undefined|string} */
FilePickerAcceptType.prototype.description;

/** @type {undefined|!Object<string,(string|!Array<string>)>} */
FilePickerAcceptType.prototype.accept;

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-filepickeroptions
 */
var FilePickerOptions = function() {};

/** @type {undefined|!Array<!FilePickerAcceptType>} */
FilePickerOptions.prototype.types;

/** @type {undefined|boolean} */
FilePickerOptions.prototype.excludeAcceptAllOption;

/**
 * @record
 * @struct
 * @extends {FilePickerOptions}
 * @see https://wicg.github.io/file-system-access/#dictdef-openfilepickeroptions
 */
var OpenFilePickerOptions = function() {};

/** @type {undefined|boolean} */
OpenFilePickerOptions.prototype.multiple;

/**
 * @record
 * @struct
 * @extends {FilePickerOptions}
 * @see https://wicg.github.io/file-system-access/#dictdef-savefilepickeroptions
 */
var SaveFilePickerOptions = function() {};

/**
 * @record
 * @struct
 * @see https://wicg.github.io/file-system-access/#dictdef-directorypickeroptions
 */
var DirectoryPickerOptions = function() {};

/**
 * @param {!OpenFilePickerOptions=} opt_options
 * @return {!Promise<!Array<!FileSystemFileHandle>>}
 * @see https://wicg.github.io/file-system-access/#local-filesystem
 */
Window.prototype.showOpenFilePicker = function(opt_options) {};

/**
 * @param {!SaveFilePickerOptions=} opt_options
 * @return {!Promise<!FileSystemFileHandle>}
 * @see https://wicg.github.io/file-system-access/#local-filesystem
 */
Window.prototype.showSaveFilePicker = function(opt_options) {};

/**
 * @param {!DirectoryPickerOptions=} opt_options
 * @return {!Promise<!FileSystemDirectoryHandle>}
 * @see https://wicg.github.io/file-system-access/#local-filesystem
 */
Window.prototype.showDirectoryPicker = function(opt_options) {};
<|endoftext|>


<commit_before>const _ = require('lodash')
const mapView = require('./mapView')
const noUiSlider = require('nouislider')
const format = require('./format')
const typeToggles = ['bubble', 'outdoor', 'indoor', 'single']
const defaults = {
    fieldToggles: {},
    typeToggles:  {},
    start:        60,
    end:          235,
    collapsed:    false
}
var settings = loadFilters() || defaults
var schedule = document.getElementById('schedule')

module.exports = {
    init: initNavigation
}

var mapMissing = true

function reportSettings(settings) {
    return `${activeFilters(settings).sort().join(' ')} ${settings.start}-${settings.end} ${settings.collapsed ? 'collapsed' : ''}`
}

function initNavigation(bindEsc) {
    activeFilters(settings).forEach(name => {
        document.getElementById(name).classList.add('inactive')
    })
    const singleToggle = document.getElementById('single')
    singleToggle.checked = 'single' in settings.typeToggles
    setContainerFilterClasses()
    elems('.filters button').forEach(el => el.addEventListener('click', toggleEvent))
    singleToggle.addEventListener('click', toggleEvent)
    function toggleEvent(e) {
        const button = e.target
        button.classList.toggle('inactive')
        const id = button.id
        toggleObj(id, settings)
        setTimeout(() => {
            schedule.classList.toggle(id)
            saveFilters()
        }, 1)
    }

    elem('.toggleInformation').addEventListener('click',() => {
        ga('send', 'event', 'Info', 'open')
        elem('.information').style.display='block'
        bindEsc()
    })
    elem('.toggleMapInformation').addEventListener('click',() => {
        elem('#map_wrapper').style.display='block'
        if (mapMissing) {
            mapView.renderMap()
            mapMissing = false
        }
        bindEsc()
    })
    toggleNavi()
    elem('.toggleFilters').addEventListener('click', () => toggle(false))
    elem('.filters .close').addEventListener('click', () => toggle(true))

    function toggle(isCollapsed) {
        settings.collapsed = isCollapsed
        toggleNavi()
        saveFilters()
    }
    initTimeFilter()
    initFeedback()
}

function initFeedback() {
    elem('.feedbackForm').addEventListener('submit', e => {
        e.preventDefault()
        var feedback = elem('.feedback')
        var text = feedback.value
        ga('send', 'event', 'Feedback', text)
        feedback.value = ''
        const submitFeedback = elem('.submitFeedback')
        submitFeedback.disabled = true
        submitFeedback.textContent = 'Palaute lähetetty'
    })
    return false
}

function toggleNavi() {
    elem('.filters').classList.toggle('collapsed', settings.collapsed)
    schedule.classList.toggle('collapsed', settings.collapsed)
}

function toggleObj(key, objRoot) {
    var obj = (typeToggles.indexOf(key) >= 0) ? objRoot.typeToggles : objRoot.fieldToggles
    if (key in obj) delete obj[key]
    else obj[key] = true

}

var all = _.range(60, 235, 5)

function initTimeFilter() {
    var slider = document.getElementById('slider')
    noUiSlider.create(slider, {
        start:   [settings.start, settings.end],
        step:    5,
        connect: true,
        range:   {
            'min': 60,
            'max': 230
        },
        format:  {
            to:   format.formatTime,
            from: x => x
        }
    })
    slider.noUiSlider.on('update', (values, endTime) => {
        var isStart = !endTime
        setStartAndEndLabels(isStart, format.parseTime(values[endTime]))
    })
    slider.noUiSlider.on('change', () => {
        setContainerFilterClasses()
        saveFilters()
    })
}
var $rangeLabel = elem('.rangeLabel')

function setStartAndEndLabels(isStart, val) {
    if (isStart) settings.start = Number(val)
    else settings.end = Number(val)
    $rangeLabel.innerHTML = format.formatTime(settings.start) + '-' + format.formatTime(settings.end)
}

function setContainerFilterClasses() {
    var hiddenTimes = all.filter(time => time < settings.start || time > settings.end)
    schedule.className = activeFilters(settings).concat(hiddenTimes.map(time => 'h' + time)).join(' ')
}

function activeFilters(settings) { return _.map(_.extend({}, settings.fieldToggles, settings.typeToggles), (v, k) => k) }

function saveFilters() {
    localStorage.setItem('filters', JSON.stringify({
        toggles:   _.extend({}, settings.fieldToggles, settings.typeToggles),
        start:     settings.start,
        end:       settings.end,
        collapsed: settings.collapsed
    }))
}

function loadFilters() {
    var jsonString = localStorage.getItem('filters')
    var parsedJson = JSON.parse(jsonString)
    if (!parsedJson) return null
    if (jsonString) ga('send', 'event', 'User settings', reportSettings(parsedJson))
    return {
        fieldToggles: _.omit(parsedJson.toggles, typeToggles),
        typeToggles:  _.pick(parsedJson.toggles, typeToggles),
        start:        parsedJson.start,
        end:          parsedJson.end,
        collapsed:    parsedJson.collapsed
    }
}

function elem(selector) { return document.querySelector(selector) }

function elems(selector) { return Array.prototype.slice.call(document.querySelectorAll(selector)) }
<commit_msg>Fix warnings by using window namespace<commit_after>const _ = require('lodash')
const mapView = require('./mapView')
const noUiSlider = require('nouislider')
const format = require('./format')
const typeToggles = ['bubble', 'outdoor', 'indoor', 'single']
const defaults = {
    fieldToggles: {},
    typeToggles:  {},
    start:        60,
    end:          235,
    collapsed:    false
}
var settings = loadFilters() || defaults
var schedule = document.getElementById('schedule')

module.exports = {
    init: initNavigation
}

var mapMissing = true

function reportSettings(settings) {
    return `${activeFilters(settings).sort().join(' ')} ${settings.start}-${settings.end} ${settings.collapsed ? 'collapsed' : ''}`
}

function initNavigation(bindEsc) {
    activeFilters(settings).forEach(name => {
        document.getElementById(name).classList.add('inactive')
    })
    const singleToggle = document.getElementById('single')
    singleToggle.checked = 'single' in settings.typeToggles
    setContainerFilterClasses()
    elems('.filters button').forEach(el => el.addEventListener('click', toggleEvent))
    singleToggle.addEventListener('click', toggleEvent)
    function toggleEvent(e) {
        const button = e.target
        button.classList.toggle('inactive')
        const id = button.id
        toggleObj(id, settings)
        setTimeout(() => {
            schedule.classList.toggle(id)
            saveFilters()
        }, 1)
    }

    elem('.toggleInformation').addEventListener('click',() => {
        window.ga('send', 'event', 'Info', 'open')
        elem('.information').style.display='block'
        bindEsc()
    })
    elem('.toggleMapInformation').addEventListener('click',() => {
        elem('#map_wrapper').style.display='block'
        if (mapMissing) {
            mapView.renderMap()
            mapMissing = false
        }
        bindEsc()
    })
    toggleNavi()
    elem('.toggleFilters').addEventListener('click', () => toggle(false))
    elem('.filters .close').addEventListener('click', () => toggle(true))

    function toggle(isCollapsed) {
        settings.collapsed = isCollapsed
        toggleNavi()
        saveFilters()
    }
    initTimeFilter()
    initFeedback()
}

function initFeedback() {
    elem('.feedbackForm').addEventListener('submit', e => {
        e.preventDefault()
        var feedback = elem('.feedback')
        var text = feedback.value
        window.ga('send', 'event', 'Feedback', text)
        feedback.value = ''
        const submitFeedback = elem('.submitFeedback')
        submitFeedback.disabled = true
        submitFeedback.textContent = 'Palaute lähetetty'
    })
    return false
}

function toggleNavi() {
    elem('.filters').classList.toggle('collapsed', settings.collapsed)
    schedule.classList.toggle('collapsed', settings.collapsed)
}

function toggleObj(key, objRoot) {
    var obj = (typeToggles.indexOf(key) >= 0) ? objRoot.typeToggles : objRoot.fieldToggles
    if (key in obj) delete obj[key]
    else obj[key] = true

}

var all = _.range(60, 235, 5)

function initTimeFilter() {
    var slider = document.getElementById('slider')
    noUiSlider.create(slider, {
        start:   [settings.start, settings.end],
        step:    5,
        connect: true,
        range:   {
            'min': 60,
            'max': 230
        },
        format:  {
            to:   format.formatTime,
            from: x => x
        }
    })
    slider.noUiSlider.on('update', (values, endTime) => {
        var isStart = !endTime
        setStartAndEndLabels(isStart, format.parseTime(values[endTime]))
    })
    slider.noUiSlider.on('change', () => {
        setContainerFilterClasses()
        saveFilters()
    })
}
var $rangeLabel = elem('.rangeLabel')

function setStartAndEndLabels(isStart, val) {
    if (isStart) settings.start = Number(val)
    else settings.end = Number(val)
    $rangeLabel.innerHTML = format.formatTime(settings.start) + '-' + format.formatTime(settings.end)
}

function setContainerFilterClasses() {
    var hiddenTimes = all.filter(time => time < settings.start || time > settings.end)
    schedule.className = activeFilters(settings).concat(hiddenTimes.map(time => 'h' + time)).join(' ')
}

function activeFilters(settings) { return _.map(_.extend({}, settings.fieldToggles, settings.typeToggles), (v, k) => k) }

function saveFilters() {
    window.localStorage.setItem('filters', JSON.stringify({
        toggles:   _.extend({}, settings.fieldToggles, settings.typeToggles),
        start:     settings.start,
        end:       settings.end,
        collapsed: settings.collapsed
    }))
}

function loadFilters() {
    var jsonString = window.localStorage.getItem('filters')
    var parsedJson = JSON.parse(jsonString)
    if (!parsedJson) return null
    if (jsonString) window.ga('send', 'event', 'User settings', reportSettings(parsedJson))
    return {
        fieldToggles: _.omit(parsedJson.toggles, typeToggles),
        typeToggles:  _.pick(parsedJson.toggles, typeToggles),
        start:        parsedJson.start,
        end:          parsedJson.end,
        collapsed:    parsedJson.collapsed
    }
}

function elem(selector) { return document.querySelector(selector) }

function elems(selector) { return Array.prototype.slice.call(document.querySelectorAll(selector)) }
<|endoftext|>


<commit_before>/***************************************************************************
 * This is the pubsub driver that should tell caspa about the melted status
 *
 * this code is more than slightly coupled with caspa's section that deals
 * with the messages. It should probably be refactored a little, things like
 * creating constants in and handling db collections in mbc-common
 ***************************************************************************/
var events = require('events');
var util = require('util');
var _ = require('underscore');
var mbc = require('mbc-common');

defaults = { // copied from caspa/models.App.Status
    _id: 2,
    piece: {
        previous: {name: ''},
        current:  {name: '', progress: '0%'},
        next:     {name: ''},
    },
    show: {
        previous: {_id: -1},
        current:  {_id: -1},
        next:     {_id: -1},
    },
    source: null,
    on_air: false,
};

function MostoMessage(value, description, message) {
    this.value = value;
    this.description = description;
    this.message = message;
}

function CaspaDriver() {
    events.EventEmitter.call(this);
    var self = this;
    this.status = _.clone(defaults);
    this.db = mbc.db();
    this.publisher = mbc.pubsub();

    CaspaDriver.prototype.setupAll = function() {
        var setups = [
            this.setupStatus.bind(this),
            this.setupMessages.bind(this),
        ];
        var sendReady = _.after(setups.length, function() {
            self.emit('ready');
        });
        setups.forEach(function(setup){
            setup(sendReady);
        });
    };

    CaspaDriver.prototype.setupStatus = function(callback) {
        var col = this.db.collection('status');
        col.findOne({_id: 2}, function(err, res) {
            if( err )
                // err.. do something?
                return;
            if( !res ) {
                // the status doesn't exist, create it
                col.save(self.status, function(err, itm) {
                    callback();
                });
            } else {
                // res existed, just signal as ready
                callback();
            }
        });
    };

    CaspaDriver.prototype.setupMessages = function(callback) {
        // I think we should assume at init there's no sticky errors?
        this.db.collection('mostomessages').remove(callback);
    };

    CaspaDriver.prototype.setStatus = function(meltedStatus) {
        // this overrides this.status with the values passed by status
        function makePiece(clip) {
            if (clip===undefined) return { name: '', _id: '' };
            return {
                name: clip.name,
                _id: clip.id
            }
        }

        var clips = meltedStatus.clips;
        var status = {
            piece: {
                previous: makePiece(meltedStatus.clip.previous),
                current:  makePiece(meltedStatus.clip.current),
                next:     makePiece(meltedStatus.clip.next),
            },
            show: {
                previous: { _id: meltedStatus.show.previous },
                current: { _id: meltedStatus.show.current },
                next: { _id: meltedStatus.show.next },
            },
            on_air: true,
        };
        status.piece.current.progress = meltedStatus.position * 100 + "%";

        this.status = _.extend(this.status, status);
        // except next. If that's undefined, I just don't know!
        this.status.show.next = status.show.next;
        this.publishStatus(status);
    };
    CaspaDriver.prototype.publishStatus = function(status) {
        this.publisher.publishJSON("mostoStatus", status)
    };

    CaspaDriver.prototype.publishMessage = function(code, description, message, sticky) {
        message = new MostoMessage(code, description, message);
        var method = 'emit';
        if( sticky ) {
            // I create an id with the timestamp to be able to cancel the error afterwards
            message.stickId = (new moment()).valueOf();
            method = 'create';
        }
        this.publisher.publishJSON(["mostoMessage", method].join('.'),
                                   { model: message });
        return message;
    };

    CaspaDriver.prototype.dropMessage = function(message) {
        this.publisher.publish("mostoMessage.delete", { model: message });
    };
}

util.inherits(CaspaDriver, events.EventEmitter);

exports = module.exports = function() {
    var driver = new CaspaDriver();
    driver.setupAll();

    return driver;
};
<commit_msg>move prototype definitions out of constructor function<commit_after>/***************************************************************************
 * This is the pubsub driver that should tell caspa about the melted status
 *
 * this code is more than slightly coupled with caspa's section that deals
 * with the messages. It should probably be refactored a little, things like
 * creating constants in and handling db collections in mbc-common
 ***************************************************************************/
var events = require('events');
var util = require('util');
var _ = require('underscore');
var mbc = require('mbc-common');

defaults = { // copied from caspa/models.App.Status
    _id: 2,
    piece: {
        previous: {name: ''},
        current:  {name: '', progress: '0%'},
        next:     {name: ''},
    },
    show: {
        previous: {_id: -1},
        current:  {_id: -1},
        next:     {_id: -1},
    },
    source: null,
    on_air: false,
};

function MostoMessage(value, description, message) {
    this.value = value;
    this.description = description;
    this.message = message;
}

function CaspaDriver() {
    events.EventEmitter.call(this);
    var self = this;
    this.status = _.clone(defaults);
    this.db = mbc.db();
    this.publisher = mbc.pubsub();
}
util.inherits(CaspaDriver, events.EventEmitter);

CaspaDriver.prototype.setupAll = function() {
    var self = this;
    var setups = [
        this.setupStatus.bind(this),
        this.setupMessages.bind(this),
    ];
    var sendReady = _.after(setups.length, function() {
        self.emit('ready');
    });
    setups.forEach(function(setup){
        setup(sendReady);
    });
};

CaspaDriver.prototype.setupStatus = function(callback) {
    var self = this;
    var col = this.db.collection('status');
    col.findOne({_id: 2}, function(err, res) {
        if( err )
            // err.. do something?
            return;
        if( !res ) {
            // the status doesn't exist, create it
            col.save(self.status, function(err, itm) {
                callback();
            });
        } else {
            // res existed, just signal as ready
            callback();
        }
    });
};

CaspaDriver.prototype.setupMessages = function(callback) {
    // I think we should assume at init there's no sticky errors?
    this.db.collection('mostomessages').remove(callback);
};

CaspaDriver.prototype.setStatus = function(meltedStatus) {
    // this overrides this.status with the values passed by status
    function makePiece(clip) {
        if (clip===undefined) return { name: '', _id: '' };
        return {
            name: clip.name,
            _id: clip.id
        }
    }

    var clips = meltedStatus.clips;
    var status = {
        piece: {
            previous: makePiece(meltedStatus.clip.previous),
            current:  makePiece(meltedStatus.clip.current),
            next:     makePiece(meltedStatus.clip.next),
        },
        show: {
            previous: { _id: meltedStatus.show.previous },
            current: { _id: meltedStatus.show.current },
            next: { _id: meltedStatus.show.next },
        },
        on_air: true,
    };
    status.piece.current.progress = meltedStatus.position * 100 + "%";

    this.status = _.extend(this.status, status);
    // except next. If that's undefined, I just don't know!
    this.status.show.next = status.show.next;
    this.publishStatus(status);
};

CaspaDriver.prototype.setStatusClip = function(statusClip) {}

CaspaDriver.prototype.publishStatus = function(status) {
    this.publisher.publishJSON("mostoStatus", status)
};

CaspaDriver.prototype.publishMessage = function(code, description, message, sticky) {
    message = new MostoMessage(code, description, message);
    var method = 'emit';
    if( sticky ) {
        // I create an id with the timestamp to be able to cancel the error afterwards
        message.stickId = (new moment()).valueOf();
        method = 'create';
    }
    this.publisher.publishJSON(["mostoMessage", method].join('.'),
                               { model: message });
    return message;
};

CaspaDriver.prototype.dropMessage = function(message) {
    this.publisher.publish("mostoMessage.delete", { model: message });
};

exports = module.exports = function() {
    var driver = new CaspaDriver();
    driver.setupAll();

    return driver;
};
<|endoftext|>


<commit_before>var app = angular.module('mergely', []);

app.directive('mergelyEditor', function() {
  return {
    restrict: 'E',
    replace: true,

    // TODO seperate this out into a seperate html template file
    template:
      '
' +
        '
' +
          '<tabset>' +
            '<tab ng-repeat="tab in tabs" heading="{{tab.heading}}" active="tab.active" disable="!tab.active" ng-click="tab.click(tab.heading)"></tab>' +
          '</tabset>' +
        '
' +
        '

' +
        '
' +
          'My File (will keep)' +
          'Other File' +
        '
' +
        '
' +
          '<button type="button" class="merge-btn" ng-class="acceptButtonClass" ng-click="_accept()">Merge</button>' +
          '<button type="button" class="merge-btn" ng-class="cancelButtonClass" ng-click="cancelCallback()">Cancel</button>' +
        '
' +
      '
',

    scope: {
      originalFiles: '=',
      otherFiles: '=',
      acceptCallback: '=',
      cancelCallback: '=',
      settings: '=',
      cancelButtonClass: '@?',
      acceptButtonClass: '@?'
    },
    controller: ["$scope", function($scope) {
      $scope.tabs = [];
      $scope.finalFiles = [];
      $scope.mergable = false;
      $scope.tabData = {};
      $scope.curTab = undefined;
      $scope.ignoreChanges = false;

      // Get the union of the two path sets
      $scope.getAllPaths = function() {
        var as = Object.keys($scope.originalFiles);
        var bs = Object.keys($scope.otherFiles);
        var paths = [];

        for (var a in as) {
          paths[a] = as[a];
        }
        for (var b in bs) {
          paths[b] = bs[b];
        }

        return paths;
      };

      // retrieves the files for the merge
      $scope.filesToMerge = function() {
        var files = {};
        var paths = $scope.getAllPaths();

        for (var i = 0; i < paths.length; i++) {
          var content, path = paths[i];

          if (path === $scope.curTab) {
            content = $('#mergely-editor').mergely('get', 'lhs');
          } else {
            content = $scope.tabData[path].lhs;
          }

          if (content.length) {
            files[path] = content;
          }
        }

        return files;
      };

      // Wrapper to accept to get the file contents before finalizing merge
      $scope._accept = function() {
        $scope.acceptCallback($scope.filesToMerge());
      };
    }],
    link: function($scope, element) {
      var getHeading = function(path) {
        if ($scope.tabData[path].lhs !== $scope.tabData[path].rhs) {
          return path + '*';
        }
        return path;
      };

      var openTab = function(file) {
        $scope.curTab = file;

        // Load tab content
        $scope.ignoreChanges = true;
        $('#mergely-editor').mergely('lhs', $scope.tabData[file].lhs);
        $('#mergely-editor').mergely('rhs', $scope.tabData[file].rhs);
        $scope.ignoreChanges = false;
      };

      var onContentChange = function() {
        if ($scope.curTab && !$scope.ignoreChanges) {
          var td = $scope.tabData[$scope.curTab];
          td.lhs = $('#mergely-editor').mergely('get', 'lhs');
          td.rhs = $('#mergely-editor').mergely('get', 'rhs');

          // Update the tab heading
          var index = $scope.tabData[$scope.curTab].index;
          $scope.$apply(function() {
            $scope.tabs[index].heading = getHeading($scope.curTab);
          });
        }
      };

      var updateTabs = function() {
        if (!Object.keys($scope.originalFiles).length ||
          !Object.keys($scope.otherFiles).length) {
          // Do nothing if both are not set yet
          return;
        }

        // update the tabs
        $scope.tabs = [];
        $scope.tabData = {};

        var paths = $scope.getAllPaths();
        var newCurTab = null;

        for (var i = 0; i < paths.length; i++) {
          var path = paths[i];

          $scope.tabData[path] = {
            lhs: $scope.originalFiles[path] || '',
            rhs: $scope.otherFiles[path] || '',
            index: -1
          };

          // Only add tabs if the sides are different or given it is the last
          // tab and we have yet to add any (to at least show the use something)
          if ($scope.tabData[path].lhs !== $scope.tabData[path].rhs ||
            (i === paths.length - 1 && !$scope.tabs.length)) {
            if (!newCurTab) {
              newCurTab = path;
            }

            $scope.tabs.push({
              heading: getHeading(path),
              active: path === newCurTab,
              click: openTab
            });

            $scope.tabData[path].index = $scope.tabs.length - 1;
          }
        }

        // make sure to goto the tab
        openTab(newCurTab);
      };

      // update tabs when files/originalFiles change
      $scope.$watch('originalFiles', updateTabs);
      $scope.$watch('otherFiles', updateTabs);

      // Default mergely settings
      $scope.settings = $scope.settings || {};
      $scope.settings.viewport = $scope.settings.viewport || true;
      $scope.settings.editor_width  = $scope.settings.editor_width  || 'auto';
      $scope.settings.editor_height = $scope.settings.editor_height || 'auto';

      // enable mergely
      $('#mergely-editor').mergely($scope.settings);

      // register code mirror callbacks
      var lcm = $('#mergely-editor').mergely('cm', 'lhs');
      var rcm = $('#mergely-editor').mergely('cm', 'rhs');

      lcm.on('changes', onContentChange);
      rcm.on('changes', onContentChange);
    }
  };
});
<commit_msg>Updated dist<commit_after>var app = angular.module('mergely', []);

app.directive('mergelyEditor', function() {
  return {
    restrict: 'E',
    replace: true,

    // TODO seperate this out into a seperate html template file
    template:
      '
' +
        '
' +
          '<tabset>' +
            '<tab ng-repeat="tab in tabs" heading="{{tab.heading}}" active="tab.active" disable="!tab.active" ng-click="tab.click(tab.heading)"></tab>' +
          '</tabset>' +
        '
' +
        '

' +
        '
' +
          'My File (will keep)' +
          'Other File' +
        '
' +
        '
' +
          '<button type="button" class="merge-btn" ng-class="acceptButtonClass" ng-click="_accept()">Merge</button>' +
          '<button type="button" class="merge-btn" ng-class="cancelButtonClass" ng-click="cancelCallback()">Cancel</button>' +
        '
' +
      '
',

    scope: {
      originalFiles: '=',
      otherFiles: '=',
      acceptCallback: '=',
      cancelCallback: '=',
      settings: '=',
      cancelButtonClass: '@?',
      acceptButtonClass: '@?'
    },
    controller: ["$scope", function($scope) {
      $scope.tabs = [];
      $scope.finalFiles = [];
      $scope.mergable = false;
      $scope.tabData = {};
      $scope.curTab = undefined;
      $scope.ignoreChanges = false;

      // Get the union of the two path sets
      $scope.getAllPaths = function() {
        var as = Object.keys($scope.originalFiles);
        var bs = Object.keys($scope.otherFiles);
        var paths = [];

        for (var a in as) {
          paths[a] = as[a];
        }
        for (var b in bs) {
          paths[b] = bs[b];
        }

        return paths;
      };

      // retrieves the files for the merge
      $scope.filesToMerge = function() {
        var files = {};
        var paths = $scope.getAllPaths();

        for (var i = 0; i < paths.length; i++) {
          var content, path = paths[i];

          if (path === $scope.curTab) {
            content = $('#mergely-editor').mergely('get', 'lhs');
          } else {
            content = $scope.tabData[path].lhs;
          }

          if (content.length) {
            files[path] = content;
          }
        }

        return files;
      };

      // Wrapper to accept to get the file contents before finalizing merge
      $scope._accept = function() {
        $scope.acceptCallback($scope.filesToMerge());
      };
    }],
    link: function($scope, element) {
      var getHeading = function(path) {
        if ($scope.tabData[path].lhs !== $scope.tabData[path].rhs) {
          return path + ' (unmerged)';
        }
        return path;
      };

      var openTab = function(file) {
        $scope.curTab = file;

        // Load tab content
        $scope.ignoreChanges = true;
        $('#mergely-editor').mergely('lhs', $scope.tabData[file].lhs);
        $('#mergely-editor').mergely('rhs', $scope.tabData[file].rhs);
        $scope.ignoreChanges = false;
      };

      var onContentChange = function() {
        if ($scope.curTab && !$scope.ignoreChanges) {
          var td = $scope.tabData[$scope.curTab];
          td.lhs = $('#mergely-editor').mergely('get', 'lhs');
          td.rhs = $('#mergely-editor').mergely('get', 'rhs');

          // Update the tab heading
          var index = $scope.tabData[$scope.curTab].index;
          $scope.$apply(function() {
            $scope.tabs[index].heading = getHeading($scope.curTab);
          });
        }
      };

      var updateTabs = function() {
        if (!Object.keys($scope.originalFiles).length ||
          !Object.keys($scope.otherFiles).length) {
          // Do nothing if both are not set yet
          return;
        }

        // update the tabs
        $scope.tabs = [];
        $scope.tabData = {};

        var paths = $scope.getAllPaths();
        var newCurTab = null;

        for (var i = 0; i < paths.length; i++) {
          var path = paths[i];

          $scope.tabData[path] = {
            lhs: $scope.originalFiles[path] || '',
            rhs: $scope.otherFiles[path] || '',
            index: -1
          };

          // Only add tabs if the sides are different or given it is the last
          // tab and we have yet to add any (to at least show the use something)
          if ($scope.tabData[path].lhs !== $scope.tabData[path].rhs ||
            (i === paths.length - 1 && !$scope.tabs.length)) {
            if (!newCurTab) {
              newCurTab = path;
            }

            $scope.tabs.push({
              heading: getHeading(path),
              active: path === newCurTab,
              click: openTab
            });

            $scope.tabData[path].index = $scope.tabs.length - 1;
          }
        }

        // make sure to goto the tab
        openTab(newCurTab);
      };

      // update tabs when files/originalFiles change
      $scope.$watch('originalFiles', updateTabs);
      $scope.$watch('otherFiles', updateTabs);

      // Default mergely settings
      $scope.settings = $scope.settings || {};
      $scope.settings.viewport = $scope.settings.viewport || true;
      $scope.settings.editor_width  = $scope.settings.editor_width  || 'auto';
      $scope.settings.editor_height = $scope.settings.editor_height || 'auto';

      // enable mergely
      $('#mergely-editor').mergely($scope.settings);

      // register code mirror callbacks
      var lcm = $('#mergely-editor').mergely('cm', 'lhs');
      var rcm = $('#mergely-editor').mergely('cm', 'rhs');

      lcm.on('changes', onContentChange);
      rcm.on('changes', onContentChange);
    }
  };
});
<|endoftext|>


<commit_before>var fs = require("fs");
var projector = require("../projector");

var GeoJsonSource = function(options) {
  this._projection = options.projection;// || "EPSG:4326"; //"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs";
  this._path = options.path; // required
  this._encoding = options.encoding || "utf8";
  this.name = options.name || options.path.slice(options.path.lastIndexOf("/") + 1);
  if (this.name.indexOf(".") !== -1) {
    this.name = this.name.slice(0, this.name.indexOf("."));
  }
  this.sourceName = this.name;

  // loading synchronization
  this._loadCallbacks = [];
  this._loading = false;

  // stored state
  this._loadError = null;
  this._data = null;
  this._projectedData = {};

};

GeoJsonSource.prototype = {
  constructor: GeoJsonSource,

  getShapes: function(minX, minY, maxX, maxY, mapProjection, callback) {
    if (this._projectedData[mapProjection]){
      callback(null, this._projectedData[mapProjection]);
    } else {
      this.load(function(error, data) {
        if (!error){
            this._project(mapProjection);
        } else {
          this._loadError = error;
        }
        callback(this._loadError, this._projectedData[mapProjection])
      }.bind(this));
    }
  },

  load: function(callback) {
    callback && this._loadCallbacks.push(callback);

    if (!this._loading && !this._loadError && !this._data) { // only load once
      this._loading = true;

      var start = Date.now();
      console.log("Loading data in " + this._path + "...");

      fs.readFile(this._path, this._encoding, function(error, content) {
        if (error) {
          this._loadError = error;
        }
        else {
          try {
            this._data = JSON.parse(content);
            console.log("Loaded in " + (Date.now() - start) + "ms");
          }
          catch (ex) {
            this._loadError = ex;
          }
        }

        this._loading = false;

        var callbacks = this._loadCallbacks;
        this._loadCallbacks = [];
        callbacks.forEach(function(callback) {
          callback(this._loadError, this._data);
        }.bind(this));
      }.bind(this));
    } else {
      var callbacks = this._loadCallbacks;
      this._loadCallbacks = [];
      callbacks.forEach(function(callback) {
        callback(this._loadError, this._data);
      }.bind(this));
    }
  },

  _project: function(mapProjection) {
    if (this._projection !== mapProjection) {
      console.log("Projecting features...");
      start = Date.now();

      this._projectedData[mapProjection] = projector.project.FeatureCollection(this._projection, mapProjection, this._data);

      console.log("Projected in " + (Date.now() - start) + "ms");
    } else {
      console.log("Projection not necessary")
        this._projectedData[mapProjection] = this._data;
    }
  }
}

module.exports = GeoJsonSource;
<commit_msg>Other minor GeoJson loader fixes<commit_after>var fs = require("fs");
var projector = require("../projector");

var GeoJsonSource = function(options) {
  this._projection = options.projection;// || "EPSG:4326"; //"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs";
  this._path = options.path; // required
  this._encoding = options.encoding || "utf8";
  this.name = options.name || options.path.slice(options.path.lastIndexOf("/") + 1);
  if (this.name.indexOf(".") !== -1) {
    this.name = this.name.slice(0, this.name.indexOf("."));
  }
  this.sourceName = this.name;

  // loading synchronization
  this._loadCallbacks = [];
  this._loading = false;

  // stored state
  this._loadError = null;
  this._data = null;
  this._projectedData = {};

};

GeoJsonSource.prototype = {
  constructor: GeoJsonSource,

  getShapes: function(minX, minY, maxX, maxY, mapProjection, callback) {
    if (this._projectedData[mapProjection]){
      callback(null, this._projectedData[mapProjection]);
    } else {
      this.load(function(error, data) {
        if (error){
          this._loadError = error;
        } else {
          this._project(mapProjection);
        }
        callback(this._loadError, this._projectedData[mapProjection])
      }.bind(this));
    }
  },

  load: function(callback) {
    callback && this._loadCallbacks.push(callback);

    if (!this._loading && !this._loadError && !this._data) { // only load once
      this._loading = true;

      var start = Date.now();
      console.log("Loading data in " + this._path + "...");

      fs.readFile(this._path, this._encoding, function(error, content) {
        if (error) {
          this._loadError = error;
        }
        else {
          try {
            this._data = JSON.parse(content);
            console.log("Loaded in " + (Date.now() - start) + "ms");
          }
          catch (ex) {
            this._loadError = ex;
          }
        }

        this._loading = false;

        var callbacks = this._loadCallbacks;
        this._loadCallbacks = [];
        callbacks.forEach(function(callback) {
          callback(this._loadError, this._data);
        }.bind(this));
      }.bind(this));
    }
    else if (!this._loading) {
      var callbacks = this._loadCallbacks;
      this._loadCallbacks = [];
      callbacks.forEach(function(callback) {
        callback(this._loadError, this._data);
      }.bind(this));
    }
  },

  _project: function(mapProjection) {
    if (this._projection !== mapProjection) {
      console.log("Projecting features...");
      start = Date.now();

      this._projectedData[mapProjection] = projector.project.FeatureCollection(this._projection, mapProjection, this._data);

      console.log("Projected in " + (Date.now() - start) + "ms");
    } else {
      console.log("Projection not necessary")
        this._projectedData[mapProjection] = this._data;
    }
  }
}

module.exports = GeoJsonSource;
<|endoftext|>


<commit_before>'use strict'

module.exports = [
  {
    user: '@michal.brasna',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@jan.pavlovsky',
    services: ['peters', 'meat-market', 'globus']
  },
  {
    user: '@ottokovarik',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@radim',
    services: ['tankovna', 'lokal-hamburk', 'u-zabranskych']
  },
  {
    user: '@tomas.pokorny',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@radek.carda',
    services: ['peters', 'globus', 'meat-market', 'lokal-hamburk']
  },
  {
    user: '@zdenek.cejka',
    services: ['peters', 'tankovna', 'u-sani', 'meat-market', 'globus']
  },
  {
    user: '@mafo',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@martin.kadlec',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@adamsobotka',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@tomasbauer',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@lucie.kusickova',
    services: [ 'tankovna', 'u-sani', 'meat-market']
  },
  {
    user: '@zdenekfilipcik',
    services: ['peters', 'tankovna', 'u-sani', 'meat-market', 'lokal-hamburk']
  },
  {
    user: '@navratj',
    services: ['tankovna', 'lokal-hamburk', 'u-zabranskych']
  },
  {
    user: '@snajby',
    services: ['peters', 'tankovna', 'u-sani', 'meat-market', 'lokal-hamburk', 'globus']
  }
]
<commit_msg>Martin má hlad<commit_after>'use strict'

module.exports = [
  {
    user: '@michal.brasna',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@jan.pavlovsky',
    services: ['peters', 'meat-market', 'globus']
  },
  {
    user: '@ottokovarik',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@radim',
    services: ['tankovna', 'lokal-hamburk', 'u-zabranskych']
  },
  {
    user: '@tomas.pokorny',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@radek.carda',
    services: ['peters', 'globus', 'meat-market', 'lokal-hamburk']
  },
  {
    user: '@zdenek.cejka',
    services: ['peters', 'tankovna', 'u-sani', 'meat-market', 'globus']
  },
  {
    user: '@mafo',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@martin.kadlec',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@adamsobotka',
    services: ['tankovna', 'lokal-hamburk']
  },
  {
    user: '@tomasbauer',
    services: ['tankovna', 'lokal-hamburk', 'globus']
  },
  {
    user: '@lucie.kusickova',
    services: [ 'tankovna', 'u-sani', 'meat-market']
  },
  {
    user: '@zdenekfilipcik',
    services: ['peters', 'tankovna', 'u-sani', 'meat-market', 'lokal-hamburk']
  },
  {
    user: '@navratj',
    services: ['tankovna', 'lokal-hamburk', 'u-zabranskych']
  },
  {
    user: '@snajby',
    services: ['peters', 'tankovna', 'u-sani', 'meat-market', 'lokal-hamburk', 'globus']
  }
]
<|endoftext|>


<commit_before>// Angular App Setup
var wilo = angular.module('wilo', []);

// Set Angular to use {[{ instead of {{ so it doesn't conflict with Jinja/Flask
wilo.config(function($interpolateProvider) {
  $interpolateProvider.startSymbol('{[{');
  $interpolateProvider.endSymbol('}]}');
});

// Controller for stop times
wilo.controller('StopsController', function($scope, $http, $timeout) {
  var getTimes = function() {
    $scope.nextTime = [];
    angular.forEach($scope.stops, function(stop, index){
      var proximoUrl = 'http://proximobus.appspot.com/agencies/sf-muni/stops/'+stop.stop_id+'/predictions.json';
      $http.get(proximoUrl).success(function(data) {
        stop.times = parseTimes(data);
        stop.progress = calculateProgressBar(stop.times, 30);
        $scope.nextTime[index] = stop.times[0];
      });
    });
    $timeout(getTimes, 30 * 1000);
  };
  $scope.stops = stops;
  $scope.nextTime = [];
  getTimes();
});

// Filter format time array into string
wilo.filter('formatted_times', function() {
  return function(times) {
    var formatted_times = times.join(', ');
    if(times.length === 0) { formatted_times = 'Unknown'; }
    return formatted_times;
  };
});

wilo.controller('ClockController', function($scope, $timeout, $sce) {
  var getHour = function(date){
    return ((date.getHours()+11)%12+1);
  };
  var getSeparator = function(date){
    var separator = ':';
    if(date.getSeconds() % 2 === 1) { separator = ''+separator+''; }
    return separator;
  };
  var getMinute = function(date){
    var minute = date.getMinutes();
    if(minute < 10) { minute = '0'+minute; }
    return minute;
  };
  var getClock = function() {
    var date = new Date();
    var clock = getHour(date) + getSeparator(date) + getMinute(date);
    $scope.clock = $sce.trustAsHtml(clock);
    $timeout(getClock, 1000);
  };
  getClock();
});

/*
 * Parse the data returned from proximobus.appspot.com
 */
function parseTimes(proximoData) {
  proximoData = proximoData.items;
  var times = [];
  for(var i=0; i<proximoData.length; i++){
    times.push(parseInt(proximoData[i].minutes));
  }
  times.sort(function(x,y){return x-y;});
  return times;
}

var colors = [2, 4, 7];
/*
 * Find widths in order to make an arrival progress bar
 */
function calculateProgressBar(times, total_time){
  // Initialize time slots
  var time_slots = new Array(total_time);
  for(var i = 0; i < time_slots.length; i++){time_slots[i] = 'default';}

  // Populate time slots with values
  var arrival, s;
  for(i = 0; i < times.length; i++){
    arrival = times[i];
    // Red
    for(var j=0; j<colors[0]; j++){
      if(arrival-j < 0 || arrival-j > total_time-1){ continue; }
      s = time_slots[arrival-j];
      if(s !== 'warning' && s !== 'success') { time_slots[arrival-j] = 'danger'; }
    }
    // Yellow
    for(j=colors[0]; j<colors[1]; j++){
      if(arrival-j < 0 || arrival-j > total_time-1){ continue; }
      s = time_slots[arrival-j];
      if(s !== 'success') { time_slots[arrival-j] = 'warning'; }
    }
    // Green
    for(j=colors[1]; j<colors[2]; j++){
      if(arrival-j < 0 || arrival-j > total_time-1){ continue; }
      time_slots[arrival-j] = 'success';
    }
  }

  // Find lengths of times
  var time_lengths = [];
  var current_length = 0;
  var current_color = time_slots[0];
  for(i=0; i<time_slots.length; i++){
    if(time_slots[i] !== current_color){
      time_lengths.push([current_color, current_length]);
      current_color = time_slots[i+1];
      current_length = 0;
    }
    current_length += 1;
  }
  time_lengths.push([current_color, current_length]);

  // Convert lengths into percentages
  for(i=0; i<time_lengths.length; i++){
    time_lengths[i][1] = 100 * time_lengths[i][1] / total_time;
  }
  return time_lengths;
}
<commit_msg>Play chime when first line arrives in 5 minutes<commit_after>// Angular App Setup
var wilo = angular.module('wilo', []);

// Set Angular to use {[{ instead of {{ so it doesn't conflict with Jinja/Flask
wilo.config(function($interpolateProvider) {
  $interpolateProvider.startSymbol('{[{');
  $interpolateProvider.endSymbol('}]}');
});

// Controller for stop times
wilo.controller('StopsController', function($scope, $http, $timeout) {
  var getTimes = function() {
    angular.forEach($scope.stops, function(stop, index){
      var proximoUrl = 'http://proximobus.appspot.com/agencies/sf-muni/stops/'+stop.stop_id+'/predictions.json';
      $http.get(proximoUrl).success(function(data) {
        stop.times = parseTimes(data);
        stop.progress = calculateProgressBar(stop.times, 30);
        chime(index, $scope.nextTime[index], stop.times[0]);
        $scope.nextTime[index] = stop.times[0];
      });
    });
    $timeout(getTimes, 30 * 1000);
  };
  $scope.stops = stops;
  $scope.nextTime = [];
  getTimes();
});

// Filter format time array into string
wilo.filter('formatted_times', function() {
  return function(times) {
    var formatted_times = times.join(', ');
    if(times.length === 0) { formatted_times = 'Unknown'; }
    return formatted_times;
  };
});

wilo.controller('ClockController', function($scope, $timeout, $sce) {
  var getHour = function(date){
    return ((date.getHours()+11)%12+1);
  };
  var getSeparator = function(date){
    var separator = ':';
    if(date.getSeconds() % 2 === 1) { separator = ''+separator+''; }
    return separator;
  };
  var getMinute = function(date){
    var minute = date.getMinutes();
    if(minute < 10) { minute = '0'+minute; }
    return minute;
  };
  var getClock = function() {
    var date = new Date();
    var clock = getHour(date) + getSeparator(date) + getMinute(date);
    $scope.clock = $sce.trustAsHtml(clock);
    $timeout(getClock, 1000);
  };
  getClock();
});

/*
 * Parse the data returned from proximobus.appspot.com
 */
function parseTimes(proximoData) {
  proximoData = proximoData.items;
  var times = [];
  for(var i=0; i<proximoData.length; i++){
    times.push(parseInt(proximoData[i].minutes));
  }
  times.sort(function(x,y){return x-y;});
  return times;
}

var colors = [2, 4, 7];
/*
 * Find widths in order to make an arrival progress bar
 */
function calculateProgressBar(times, total_time){
  // Initialize time slots
  var time_slots = new Array(total_time);
  for(var i = 0; i < time_slots.length; i++){time_slots[i] = 'default';}

  // Populate time slots with values
  var arrival, s;
  for(i = 0; i < times.length; i++){
    arrival = times[i];
    // Red
    for(var j=0; j<colors[0]; j++){
      if(arrival-j < 0 || arrival-j > total_time-1){ continue; }
      s = time_slots[arrival-j];
      if(s !== 'warning' && s !== 'success') { time_slots[arrival-j] = 'danger'; }
    }
    // Yellow
    for(j=colors[0]; j<colors[1]; j++){
      if(arrival-j < 0 || arrival-j > total_time-1){ continue; }
      s = time_slots[arrival-j];
      if(s !== 'success') { time_slots[arrival-j] = 'warning'; }
    }
    // Green
    for(j=colors[1]; j<colors[2]; j++){
      if(arrival-j < 0 || arrival-j > total_time-1){ continue; }
      time_slots[arrival-j] = 'success';
    }
  }

  // Find lengths of times
  var time_lengths = [];
  var current_length = 0;
  var current_color = time_slots[0];
  for(i=0; i<time_slots.length; i++){
    if(time_slots[i] !== current_color){
      time_lengths.push([current_color, current_length]);
      current_color = time_slots[i+1];
      current_length = 0;
    }
    current_length += 1;
  }
  time_lengths.push([current_color, current_length]);

  // Convert lengths into percentages
  for(i=0; i<time_lengths.length; i++){
    time_lengths[i][1] = 100 * time_lengths[i][1] / total_time;
  }
  return time_lengths;
}

function chime(index, oldTime, newTime) {
  if(index === 0 && oldTime > 5 && newTime <= 5) {
    var audio = new Audio("/static/chime.mp3");
    audio.play();
  }
}
<|endoftext|>


<commit_before>// Arsh Chauhan
// Based on code by Tristan Van Cise
// telemetry.js: Telemetry viewer for Aurora Robotics
// LCreated: 10/10/2016
// Last edited: 10/11/2016

function robot_telemetry_t(div,robot,sim)
{
    if (!div)
        return null;

    this.div = div;

    if (!robot)
       {
            this.telemetry =
            {
                power:
                {
                    left:0.0,
                    right:0.0,
                    mine:0.0,
                    dump:0.0,
                    roll:0.0
                },
                location:
                {
                    x:0.0,
                    y:0.0,
                    angle:0.0
                }
            };
        }

    else
        this.telemetry = robot.telemetry;

    if(sim)
        this.sim.power = sim.power;

    this.telem_rows = {};
    this.create_telemetry_gui();

    var _this = this;
    this.update_interval = setInterval(function()
        {
            _this.update_telemetry();
        },1000);

}

//PRIVATE FUNCTION DO NOT CALL OUTSIDE OF CONSTRUCTOR
robot_telemetry_t.prototype.create_telemetry_gui = function()
{
    this.table = document.createElement('table');
    this.table.className= 'telemetry_table';

    this.heading_row = document.createElement('tr');
    this.heading_row.appendChild(document.createElement('td')).appendChild(document.createElement('th')).appendChild(document.createTextNode("Sensor"));
    this.heading_row.appendChild(document.createElement('td')).appendChild(document.createElement('th')).appendChild(document.createTextNode("Value"));

    this.div.appendChild(this.table);
    this.table.appendChild(this.heading_row);

    for (var prop in this.telemetry)
    {
        this.telem_rows[prop] = {};

        for (var sensor in this.telemetry[prop])
        {
            var row = this.table.appendChild(document.createElement('tr'));
            var col_name = row.appendChild(document.createElement('td')).appendChild(document.createTextNode(sensor));
            var textnode=document.createTextNode("");
            var col_value = row.appendChild(document.createElement('td')).appendChild(textnode);
            this.telem_rows[prop][sensor] = textnode;
        }

    }
    var cells = document.getElementsByTagName('td');
    for (var i=0;i<cells.length;++i) //Add class to all cells on page
    {
        cells[i].className = 'telemetry_cell';
    }
}

robot_telemetry_t.prototype.update_telemetry = function()
{
    //FIX ME: Remove once real telemetry is available
    this.telemetry.power.left = (Math.random()*30).toFixed(2);
    this.telemetry.power.right = (Math.random()*60).toFixed(2);
    this.telemetry.power.mine = (Math.random()*90).toFixed(2);
    this.telemetry.power.dump = (Math.random()).toFixed(2);
    this.telemetry.power.roll = (Math.random()).toFixed(2);

    for (var prop in this.telemetry)
    {
        for (var sensor in this.telemetry[prop])
        {
            this.telem_rows[prop][sensor].nodeValue = this.telemetry[prop][sensor];
        }

    }
}
<commit_msg>Added random location and angle telemetry<commit_after>// Arsh Chauhan
// Based on code by Tristan Van Cise
// telemetry.js: Telemetry viewer for Aurora Robotics
// LCreated: 10/10/2016
// Last edited: 10/11/2016

function robot_telemetry_t(div,robot,sim)
{
    if (!div)
        return null;

    this.div = div;

    if (!robot)
       {
            this.telemetry =
            {
                power:
                {
                    left:0.0,
                    right:0.0,
                    mine:0.0,
                    dump:0.0,
                    roll:0.0
                },
                location:
                {
                    x:0.0,
                    y:0.0,
                    angle:0.0
                }
            };
        }

    else
        this.telemetry = robot.telemetry;

    if(sim)
        this.telemetry = sim.telemetry;

    this.telem_rows = {};
    this.create_telemetry_gui();

    var _this = this;
    this.update_interval = setInterval(function()
        {
            _this.update_telemetry();
        },1000);

}

//PRIVATE FUNCTION DO NOT CALL OUTSIDE OF CONSTRUCTOR
robot_telemetry_t.prototype.create_telemetry_gui = function()
{
    this.table = document.createElement('table');
    this.table.className= 'telemetry_table';

    this.heading_row = document.createElement('tr');
    this.heading_row.appendChild(document.createElement('td')).appendChild(document.createElement('th')).appendChild(document.createTextNode("Sensor"));
    this.heading_row.appendChild(document.createElement('td')).appendChild(document.createElement('th')).appendChild(document.createTextNode("Value"));

    this.div.appendChild(this.table);
    this.table.appendChild(this.heading_row);

    for (var prop in this.telemetry)
    {
        this.telem_rows[prop] = {};

        for (var sensor in this.telemetry[prop])
        {
            var row = this.table.appendChild(document.createElement('tr'));
            var col_name = row.appendChild(document.createElement('td')).appendChild(document.createTextNode(sensor));
            var textnode=document.createTextNode("");
            var col_value = row.appendChild(document.createElement('td')).appendChild(textnode);
            this.telem_rows[prop][sensor] = textnode;
        }

    }
    var cells = document.getElementsByTagName('td');
    for (var i=0;i<cells.length;++i) //Add class to all cells on page
    {
        cells[i].className = 'telemetry_cell';
    }
}

robot_telemetry_t.prototype.update_telemetry = function()
{
    //FIX ME: Remove once real telemetry is available
    //Random sensor telemetry
    this.telemetry.power.left = (Math.random()*30).toFixed(2);
    this.telemetry.power.right = (Math.random()*60).toFixed(2);
    this.telemetry.power.mine = (Math.random()*90).toFixed(2);
    this.telemetry.power.dump = (Math.random()).toFixed(2);
    this.telemetry.power.roll = (Math.random()).toFixed(2);

    //Random location telemetry
    this.telemetry.location.x = (Math.random()*(194-(-194))-194).toFixed(2);
    this.telemetry.location.y = (Math.random()*738).toFixed(2);
    this.telemetry.location.angle = (Math.random()*(180-(-180))-180).toFixed(2)

    for (var prop in this.telemetry)
    {
        for (var sensor in this.telemetry[prop])
        {
            this.telem_rows[prop][sensor].nodeValue = this.telemetry[prop][sensor];
        }

    }
}
<|endoftext|>


<commit_before>import { List, Map} from 'immutable';
import uuid from 'node-uuid';
import moment from 'moment';

console.log("loading irc-reducers");

import {
	INIT_CONNECTION,
    SET_CONNECTED,
    RECEIVE_MESSAGE,
    SET_CHANNEL_TOPIC,
    SET_CHANNEL_USERS,
    SET_CURRENT_CHANNEL,
    JOIN_CHANNEL,
    MESSAGE_TO_CHANNEL
} from '../actions/irc-actions';

const defaultState = {
    io: null,
    messages: List(),
    channels: Map(),
    users: List(),
    currentChannel: null,
    connected: false,
    topic: null
};

function channelStructure() {
    return {
        name: null,
        topic: null,
        messages: List(),
        users: List()
    };
}

export default function(state = defaultState, action) {
	console.log("type: " + action.type)
    switch (action.type) {
    	case INIT_CONNECTION:
    		return {
                ...state,
                io: action.payload
            }
    		break;
        case SET_CONNECTED:
            return {
                ...state,
                connected: action.payload
            }
            break;
        case RECEIVE_MESSAGE:
            return {
                ...state,
                messages: state.messages.push({
                    message: action.payload,
                    timestamp: moment().valueOf()
                })
            }
            break;
        case JOIN_CHANNEL:

            var channels = state.channels;
            var channel = channelStructure();

            if (!channels.has(action.payload)) {
                channel.name = action.payload;
            }
            console.log("JOIN_CHANNEL, channel name: " + action.payload);
            console.log("JOIN_CHANNEL: channel exists for " + action.payload + ": " + channels.has(action.payload));
            return {
                ...state,
                channels: channels.set(action.payload, channel),
                activeChannel: action.payload,
                messages: List(),
                users: List()
            }

            break;
        case SET_CHANNEL_TOPIC:
            console.log("SET_CHANNEL_TOPIC, payload: " + JSON.stringify(action.payload));

            var channels = state.channels;
            console.log("SET_CHANNEL_TOPIC, channels: " + JSON.stringify(channels));
            console.log("SET_CHANNEL_TOPIC: channel exists for " + action.payload.channelName + ": " + channels.has(action.payload.channelName));

            var channel = channels.get(action.payload.channelName);
            channel.topic = action.payload.topic;

            return {
                ...state,
                channels: channels.set(action.payload.channelName, channel),
                topic: action.payload.topic
            }
            break;
        case SET_CHANNEL_USERS:
            var channel = null;
            var channels = state.channels;
            console.log("SET_CHANNEL_USERS: channel exists for " + action.payload.channel + ": " + channels.has(action.payload.channel));
            if (!channels.has(action.payload.channel)) {
                channel = {
                    name: action.payload.channel,
                    users: action.payload.users
                }
            } else {
                channel = channels.get(action.payload.channel);
            }

            channels = channels.set(action.payload.channel, channel);
            console.log("SET_CHANNEL_USERS, channels: " + JSON.stringify(channels));
            return {
                ...state,
                channels: channels,
                users: List(action.payload.users)
            }
            break;
        case SET_CURRENT_CHANNEL:

            var channel = state.channels.get(action.payload);

            return {
                ...state,
                activeChannel: action.payload,
                messages: channel.messages,
                users: channel.users
            }
            break;
        case MESSAGE_TO_CHANNEL:
            let userMessage = action.payload;
            console.log("MESSAGE_TO_CHANNEL: " + JSON.stringify(userMessage));
            console.log("MESSAGE_TO_CHANNEL: channel exists for " + state.activeChannel + ": " + state.channels.has(state.activeChannel));
            console.log("MESSAGE_TO_CHANNEL: channels " + JSON.stringify(state.channels));
            console.log("MESSAGE_TO_CHANNEL, active channel: " + state.activeChannel);
            var channel = state.channels.get(userMessage.receiver);
            var messages = state.messages;

            if (channel.name == state.activeChannel) {
                var newMessage = {message: userMessage.message};
                console.log("YIPPII");
                messages = channel.messages.push(newMessage);
                channel.messages = messages;
            }

            console.log("MESSAGE_TO_CHANNEL active channel messages: " + JSON.stringify(messages));

            return {
                ...state,
                channels: state.channels.set(channel.name, channel),
                messages: messages
            }
            break;
        default:
            return state;
    }
};
<commit_msg>now messages sent to a channel taht is not active, will show up, when said channel is made active<commit_after>import { List, Map} from 'immutable';
import uuid from 'node-uuid';
import moment from 'moment';

console.log("loading irc-reducers");

import {
	INIT_CONNECTION,
    SET_CONNECTED,
    RECEIVE_MESSAGE,
    SET_CHANNEL_TOPIC,
    SET_CHANNEL_USERS,
    SET_CURRENT_CHANNEL,
    JOIN_CHANNEL,
    MESSAGE_TO_CHANNEL
} from '../actions/irc-actions';

const defaultState = {
    io: null,
    messages: List(),
    channels: Map(),
    users: List(),
    currentChannel: null,
    connected: false,
    topic: null
};

function channelStructure() {
    return {
        name: null,
        topic: null,
        messages: List(),
        users: List()
    };
}

export default function(state = defaultState, action) {
	console.log("type: " + action.type)
    switch (action.type) {
    	case INIT_CONNECTION:
    		return {
                ...state,
                io: action.payload
            }
    		break;
        case SET_CONNECTED:
            return {
                ...state,
                connected: action.payload
            }
            break;
        case RECEIVE_MESSAGE:
            return {
                ...state,
                messages: state.messages.push({
                    message: action.payload,
                    timestamp: moment().valueOf()
                })
            }
            break;
        case JOIN_CHANNEL:

            var channels = state.channels;
            var channel = channelStructure();

            if (!channels.has(action.payload)) {
                channel.name = action.payload;
            }
            console.log("JOIN_CHANNEL, channel name: " + action.payload);
            console.log("JOIN_CHANNEL: channel exists for " + action.payload + ": " + channels.has(action.payload));
            return {
                ...state,
                channels: channels.set(action.payload, channel),
                activeChannel: action.payload,
                messages: List(),
                users: List()
            }

            break;
        case SET_CHANNEL_TOPIC:
            console.log("SET_CHANNEL_TOPIC, payload: " + JSON.stringify(action.payload));

            var channels = state.channels;
            console.log("SET_CHANNEL_TOPIC, channels: " + JSON.stringify(channels));
            console.log("SET_CHANNEL_TOPIC: channel exists for " + action.payload.channelName + ": " + channels.has(action.payload.channelName));

            var channel = channels.get(action.payload.channelName);
            channel.topic = action.payload.topic;

            return {
                ...state,
                channels: channels.set(action.payload.channelName, channel),
                topic: action.payload.topic
            }
            break;
        case SET_CHANNEL_USERS:
            var channel = null;
            var channels = state.channels;
            console.log("SET_CHANNEL_USERS: channel exists for " + action.payload.channel + ": " + channels.has(action.payload.channel));
            if (!channels.has(action.payload.channel)) {
                channel = {
                    name: action.payload.channel,
                    users: action.payload.users
                }
            } else {
                channel = channels.get(action.payload.channel);
            }

            channels = channels.set(action.payload.channel, channel);
            console.log("SET_CHANNEL_USERS, channels: " + JSON.stringify(channels));
            return {
                ...state,
                channels: channels,
                users: List(action.payload.users)
            }
            break;
        case SET_CURRENT_CHANNEL:

            var channel = state.channels.get(action.payload);
            console.log("SET_CURRENT_CHANNEL: " + JSON.stringify(channel.messages));
            return {
                ...state,
                activeChannel: action.payload,
                messages: channel.messages,
                users: channel.users
            }
            break;
        case MESSAGE_TO_CHANNEL:
            let userMessage = action.payload;

            var channel = state.channels.get(userMessage.receiver);
            var messages = state.messages;
            var newMessage = {message: userMessage.message};

            channel.messages = channel.messages.push(newMessage);

            if (channel.name == state.activeChannel) {
                messages = channel.messages;
            }

            return {
                ...state,
                channels: state.channels.set(channel.name, channel),
                messages: messages
            }
            break;
        default:
            return state;
    }
};
<|endoftext|>


<commit_before>/*
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

var assert = require('power-assert');
var Some = require('../src/index').Some;
var None = require('../src/index').None;

describe('Option<T>.map()', function(){
    describe('self is `None`', function () {
        var option = null;
        var isNotCalled = true;

        before(function(){
            var none = new None();
            option = none.map(function(){
                isNotCalled = false;
            });
        });

        it('the returned value shoule be `None`: 1', function() {
            assert.strictEqual(option.isSome, false);
        });

        it('the returned value shoule be `None`: 2', function() {
            assert.ok(option instanceof None);
        });

        it('the passed function should not be called', function() {
            assert.strictEqual(isNotCalled, true);
        });
    });

    describe('self is `Some<T>`', function () {
        var EXPECTED = "1";
        var option = null;

        before(function(){
            var some = new Some(1);
            option = some.map(function(val){
                assert.notStrictEqual(val !== EXPECTED);
                return EXPECTED;
            });
        });

        it('the returned value shoule be `Some<T>`: 1', function() {
            assert.ok(option instanceof Some);
        });

        it('the returned value shoule be `Some<T>`: 2', function() {
            assert.strictEqual(option.unwrap(), EXPECTED);
        });
    });
});
<commit_msg>Use assert.notStrictEqual() correctly.<commit_after>/*
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

var assert = require('power-assert');
var Some = require('../src/index').Some;
var None = require('../src/index').None;

describe('Option<T>.map()', function(){
    describe('self is `None`', function () {
        var option = null;
        var isNotCalled = true;

        before(function(){
            var none = new None();
            option = none.map(function(){
                isNotCalled = false;
            });
        });

        it('the returned value shoule be `None`: 1', function() {
            assert.strictEqual(option.isSome, false);
        });

        it('the returned value shoule be `None`: 2', function() {
            assert.ok(option instanceof None);
        });

        it('the passed function should not be called', function() {
            assert.strictEqual(isNotCalled, true);
        });
    });

    describe('self is `Some<T>`', function () {
        var EXPECTED = "1";
        var option = null;

        before(function(){
            var some = new Some(1);
            option = some.map(function(val){
                assert.notStrictEqual(val, EXPECTED);
                return EXPECTED;
            });
        });

        it('the returned value shoule be `Some<T>`: 1', function() {
            assert.ok(option instanceof Some);
        });

        it('the returned value shoule be `Some<T>`: 2', function() {
            assert.strictEqual(option.unwrap(), EXPECTED);
        });
    });
});
<|endoftext|>


<commit_before>//algorithms by Michael Leonffu
var juicyCalculator = require('./juicyCalculator')

module.exports = {
	juicyCalculator: juicyCalculator
}
// To use in another file:
// var algorithms = require('./algorithms')<commit_msg>Fixed and addedm odularilty to algorithms<commit_after>//algorithms by Michael Leonffu
var juicyCalculator = require('./juicyCalculator')
var calculatedAverageSimple = require('./calculatedAverageSimple')
var misc = require('./misc')

var algorithmLoader = function(algorithmName, eventData, query){
	if(algorithmName === 'simpleOPR'){
		return calculatedAverageSimple.OPR(eventData, query)
	}
	// if(algorithmName === 'CCWM'){
	// 	return calculatedAverageSimple.CCWM(eventData, query)
	// }
	if(algorithmName === 'random'){
		return misc.random(eventData, query)
	}
	// if(algorithmName === 'null'){
	// 	return misc.null(eventData, query)
	// }
	return -1
}

module.exports = {
	juicyCalculator: juicyCalculator,
	calculatedAverageSimple: calculatedAverageSimple,
	misc: misc,
	algorithmLoader: algorithmLoader
}
// To use in another file:
// var algorithms = require('./algorithms')<|endoftext|>


<commit_before>class SimulationController extends HTMLElement {
    constructor() {
        super();
        this.innerHTML = `

                    <button id='slider-prev'>

                    </button>
                    <button id='slider-play-pause'>

                    </button>
                    <button id='slider-next'>

                    </button>

        `;
        this.currentFrame = 0;
        this.playing = false;
    }

    connectedCallback() {
        const container = this.querySelector('.slider-container');
        const sliderHead = this.querySelector('#slider-head');
        const sliderBar = this.querySelector('#slider-bar');
        sliderHead.onmousedown = (e) => this.dragMouseDown(e);
        sliderBar.onclick = (e) => this.clickBar(e);
        container.addEventListener('dblclick', (e) => {
            e.stopPropagation();
        });
        container.addEventListener('mousedown', (e) => {
            e.stopPropagation();
        })
        this.querySelector('#slider-play-pause').onclick = () => this.playPause();
        this.querySelector('#slider-prev').onclick = () => this.prevFrame(5);
        this.querySelector('#slider-next').onclick = () => this.nextFrame(5);
    }

    disconnectedCallback() {
        this.querySelector('.slider-container').removeEventListener();
    }

    updateSlider() {
        setup_for_time(this.currentFrame);
        const sliderHead = this.querySelector('#slider-head');
        let percentage = Math.floor((this.currentFrame / sorted_timestamps.length) * 95);
        sliderHead.style.left = percentage + '%';
    }

    playPause() {
        const playPauseButton = document.querySelector('#slider-play-pause');
        const prevButton = document.querySelector('#slider-prev');
        const nextButton = document.querySelector('#slider-next');
        this.playing = !this.playing;
        if (!this.playing) {
            playPauseButton.firstElementChild.src = 'icons/play_arrow-24px.svg';
            prevButton.disabled = false;
            nextButton.disabled = false;
        } else {
            playPauseButton.firstElementChild.src = 'icons/pause-24px.svg';
            prevButton.disabled = true;
            nextButton.disabled = true;
            this.play();
        }
    }

    play() {
        if (this.playing) {
            this.nextFrame(5);
            if (this.currentFrame == sorted_timestamps.length-1){
                window.setTimeout(() => this.play(), 1000);
            } else {
                window.setTimeout(() => this.play(), 330);
            }
        }
    }

    nextFrame(recursionDepth) {
        if (recursionDepth == 0) return;
        let nextFrame = (this.currentFrame + 1) % sorted_timestamps.length;
        if(this.frameReady(nextFrame)) {
            this.currentFrame = nextFrame;
            // current_frame = nextFrame;
            this.updateSlider();
        } else {
            // if the next frame is not ready, preload further and wait longer
            window.setTimeout(() => this.nextFrame(recursionDepth - 1), 500);
            preload_variables(nextFrame, 8);
        }
    }

    prevFrame(recursionDepth) {
        if (recursionDepth == 0) return;
        let prevFrame = (this.currentFrame - 1) % sorted_timestamps.length;
        if (prevFrame < 0) prevFrame += sorted_timestamps.length;
        if(this.frameReady(prevFrame)) {
            this.currentFrame = prevFrame;
            // current_frame = prevFrame;
            this.updateSlider();
        } else {
            window.setTimeout(() => this.prevFrame(recursionDepth - 1), 500);
            preload_variables(prevFrame, 1);
        }
    }

    frameReady(frame_ndx) {
    // for all layers currently displayed
        for(var key in current_display) {
            // if the current frame is not preloaded yet
            if(!(frame_ndx in preloaded[key])) return false;
            // check if the raster has a colorbar
            var cb_key = key + '_cb';
            if(cb_key in preloaded) {
                // it does, is it preloaded?
                if (!(frame_ndx in preloaded[cb_key])) {
                    return false;
                }
            }
        }
        return true;
    }

    dragMouseDown(e) {
          e = e || window.event;
          e.stopPropagation();
          // get the mouse cursor position at startup:
          var pos3 = e.clientX;
          var originalFrame = this.currentFrame;
          document.onmouseup = () => {
            document.onmouseup = null;
            document.onmousemove = null;
          };
          // call a function whenever the cursor moves:
          document.onmousemove = (e2) => {
            e2 = e2 || window.event;
            e2.preventDefault();
            // calculate the new cursor position:
            let diff = Math.floor((e2.clientX - pos3) / 300 * sorted_timestamps.length - 1);

            let newFrame = originalFrame + diff;
            this.currentFrame = Math.max(Math.min(sorted_timestamps.length-1, newFrame), 0);

            this.updateSlider();
          }
    }

    clickBar(e) {
        const head = this.querySelector('#slider-head').getBoundingClientRect();
        let diff = Math.floor((e.clientX - head.left) / 300 * sorted_timestamps.length - 1);
        this.currentFrame += diff;
        this.updateSlider();
    }
}

window.customElements.define('simulation-controller', SimulationController);<commit_msg>Add documentation for simulationController<commit_after>/**
 * A Componet that builds the animation controller for the simulation. Creates a UI component that
 * includes a play / pause / prev / next buttons to iterate through the simulation. Also includes a
 * slider bar with a head that indicates relative position in animation that can be dragged to a
 * specific location. Bar itself can also be clicked to seek to a specific position.
 */
class SimulationController extends HTMLElement {
    constructor() {
        super();
        this.innerHTML = `

                    <button id='slider-prev'>

                    </button>
                    <button id='slider-play-pause'>

                    </button>
                    <button id='slider-next'>

                    </button>

        `;
        this.currentFrame = 0;
        this.playing = false;
    }

    /** Called when component is attached to DOM. Sets up functionality for buttons and slider. */
    connectedCallback() {
        const container = this.querySelector('.slider-container');
        const sliderHead = this.querySelector('#slider-head');
        const sliderBar = this.querySelector('#slider-bar');
        sliderHead.onmousedown = (e) => this.dragSliderHead(e);
        sliderBar.onclick = (e) => this.clickBar(e);
        container.addEventListener('dblclick', (e) => {
            e.stopPropagation();
        });
        container.addEventListener('mousedown', (e) => {
            e.stopPropagation();
        })
        this.querySelector('#slider-play-pause').onclick = () => this.playPause();
        this.querySelector('#slider-prev').onclick = () => this.prevFrame(5);
        this.querySelector('#slider-next').onclick = () => this.nextFrame(5);
    }

    /** Called to update the UI when the currentFrame has been updated. */
    updateSlider() {
        setup_for_time(this.currentFrame);
        const sliderHead = this.querySelector('#slider-head');
        let percentage = Math.floor((this.currentFrame / sorted_timestamps.length) * 95);
        sliderHead.style.left = percentage + '%';
    }

    /** Called when play/pause button clicked. Starts animation, disables prev / next buttons
     * changes play icon to pause icon. */
    playPause() {
        const playPauseButton = document.querySelector('#slider-play-pause');
        const prevButton = document.querySelector('#slider-prev');
        const nextButton = document.querySelector('#slider-next');
        this.playing = !this.playing;
        if (!this.playing) {
            playPauseButton.firstElementChild.src = 'icons/play_arrow-24px.svg';
            prevButton.disabled = false;
            nextButton.disabled = false;
        } else {
            playPauseButton.firstElementChild.src = 'icons/pause-24px.svg';
            prevButton.disabled = true;
            nextButton.disabled = true;
            this.play();
        }
    }

    /** Iterates to next frame while still playing */
    play() {
        if (this.playing) {
            this.nextFrame(5);
            if (this.currentFrame == sorted_timestamps.length-1){
                window.setTimeout(() => this.play(), 1000);
            } else {
                window.setTimeout(() => this.play(), 330);
            }
        }
    }

    /** Moves one frame to the right. */
    nextFrame(recursionDepth) {
        if (recursionDepth == 0) return;
        let nextFrame = (this.currentFrame + 1) % sorted_timestamps.length;
        if(this.frameReady(nextFrame)) {
            this.currentFrame = nextFrame;
            // current_frame = nextFrame;
            this.updateSlider();
        } else {
            // if the next frame is not ready, preload further and wait longer
            window.setTimeout(() => this.nextFrame(recursionDepth - 1), 500);
            preload_variables(nextFrame, 8);
        }
    }

    /** Moves one frame to the left. */
    prevFrame(recursionDepth) {
        if (recursionDepth == 0) return;
        let prevFrame = (this.currentFrame - 1) % sorted_timestamps.length;
        if (prevFrame < 0) prevFrame += sorted_timestamps.length;
        if(this.frameReady(prevFrame)) {
            this.currentFrame = prevFrame;
            // current_frame = prevFrame;
            this.updateSlider();
        } else {
            window.setTimeout(() => this.prevFrame(recursionDepth - 1), 500);
            preload_variables(prevFrame, 1);
        }
    }

    /** Returns boolean indicating if frame_ndx has been loaded */
    frameReady(frame_ndx) {
    // for all layers currently displayed
        for(var key in current_display) {
            // if the current frame is not preloaded yet
            if(!(frame_ndx in preloaded[key])) return false;
            // check if the raster has a colorbar
            var cb_key = key + '_cb';
            if(cb_key in preloaded) {
                // it does, is it preloaded?
                if (!(frame_ndx in preloaded[cb_key])) {
                    return false;
                }
            }
        }
        return true;
    }

    /** Called when slider head is dragged. As dragged, calculates distance dragged and updates
     * currentFrame according to the offset.
     */
    dragSliderHead(e) {
          e = e || window.event;
          e.stopPropagation();
          // get the mouse cursor position at startup:
          var pos3 = e.clientX;
          var originalFrame = this.currentFrame;
          document.onmouseup = () => {
            document.onmouseup = null;
            document.onmousemove = null;
          };
          // call a function whenever the cursor moves:
          document.onmousemove = (e2) => {
            e2 = e2 || window.event;
            e2.preventDefault();
            // calculate the new cursor position:
            let diff = Math.floor((e2.clientX - pos3) / 300 * sorted_timestamps.length - 1);

            let newFrame = originalFrame + diff;
            this.currentFrame = Math.max(Math.min(sorted_timestamps.length-1, newFrame), 0);

            this.updateSlider();
          }
    }

    /** Called when the slider bar is cicked. Calculates distance between slider-head and click
     * location. Updates the currentFrame accordingly and calls updateSlider
     */
    clickBar(e) {
        const head = this.querySelector('#slider-head').getBoundingClientRect();
        let diff = Math.floor((e.clientX - head.left) / 300 * sorted_timestamps.length - 1);
        this.currentFrame += diff;
        this.updateSlider();
    }

    /** Called when Component is removed from the DOM. Remove EventListners */
    disconnectedCallback() {
        this.querySelector('.slider-container').removeEventListener();
    }
}

window.customElements.define('simulation-controller', SimulationController);<|endoftext|>


<commit_before>const { join, resolve } = require('path')
const { cache_path: cachePath, source_path: sourcePath, additional_paths: additionalPaths } = require('../config')
const { nodeEnv } = require('../env')

// Process application Javascript code with Babel.
// Uses application .babelrc to apply any transformations
module.exports = {
  test: /\.(js|jsx|mjs|ts|tsx)?(\.erb)?$/,
  include: [sourcePath, ...additionalPaths].map((p) => resolve(p)),
  exclude: /node_modules/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: join(cachePath, 'babel-loader-node-modules'),
        cacheCompression: nodeEnv === 'production',
        compact: nodeEnv === 'production'
      }
    }
  ]
}
<commit_msg>De-symlink paths in babel loader to match Webpack (#2329)<commit_after>const { join, resolve } = require('path')
const { realpathSync } = require('fs')
const { cache_path: cachePath, source_path: sourcePath, additional_paths: additionalPaths } = require('../config')
const { nodeEnv } = require('../env')

// Process application Javascript code with Babel.
// Uses application .babelrc to apply any transformations
module.exports = {
  test: /\.(js|jsx|mjs|ts|tsx)?(\.erb)?$/,
  include: [sourcePath, ...additionalPaths].map((p) => {
    try {
      return realpathSync(p)
    } catch (e) {
      return resolve(p)
    }
  }),
  exclude: /node_modules/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: join(cachePath, 'babel-loader-node-modules'),
        cacheCompression: nodeEnv === 'production',
        compact: nodeEnv === 'production'
      }
    }
  ]
}
<|endoftext|>