<commit_before>"use strict";

let http = require('http');
let url = require('url');

const LEVELS = {
    "Verbose": "Verbose",
    "Debug": "Debug",
    "Information" : "Information",
    "Warning": "Warning",
    "Error": "Error",
    "Fatal": "Fatal"
};

const HEADER = "{Events:[";
const FOOTER = "]}";
const HEADER_FOOTER_BYTES = Buffer.byteLength(HEADER, 'utf8') + Buffer.byteLength(FOOTER, 'utf8');

class SeqLogger {
    constructor(config) {
        let dflt = {
            serverUrl: 'http://localhost:5341',
            apiKey: null,
            maxBatchingTime: 2000,
            eventSizeLimit: 256 * 1024,
            batchSizeLimit: 1024 * 1024,
            onError: e => { console.error("[seq]", e); }
        };
        let cfg = config || dflt;
        var serverUrl = cfg.serverUrl || dflt.serverUrl;
        if (!serverUrl.endsWith('/')) {
            serverUrl += '/';
        }
        this._endpoint = url.parse(serverUrl + 'api/events/raw');
        this._apiKey = cfg.apiKey || dflt.apiKey;
        this._maxBatchingTime = cfg.maxBatchingTime || dflt.maxBatchingTime;
        this._eventSizeLimit = cfg.eventSizeLimit || dflt.eventSizeLimit;
        this._batchSizeLimit = cfg.batchSizeLimit || dflt.batchSizeLimit;
        this._onError = cfg.onError || dflt.onError;
        this._queue = [];
        this._timer = null;
        this._closed = false;
        this._activeShipper = null;
    }

    // Flush events queued at the time of the call, and wait for pending writes to complete
    // regardless of configured batching/timers.
    flush() {
        return this._ship();
    }

    // Flush then close the logger, destroying timers and other resources.
    close() {
        if (this._closed) {
            throw new Error('The logger has already been closed.');
        }

        this._closed = true;
        this._clearTimer();

        return this.flush();
    }

    // Enqueue an event in Seq format.
    emit(event) {
        if (!event) {
            throw new Error('An event must be provided');
        }
        if (this._closed) {
            return;
        }
        let norm = this._toWireFormat(event);
        this._queue.push(norm);
        if (!this._activeShipper) {
            this._setTimer();
        }
    }

    _setTimer() {
        if (this._timer !== null) {
            return;
        }

        this._timer = setTimeout(() => {
            this._timer = null;
            this._onTimer();
        }, this._maxBatchingTime);
    }

    _clearTimer() {
        if (this._timer !== null) {
            clearTimeout(this._timer);
            this._timer = null;
        }
    }

    _onTimer() {
        if (!this._activeShipper) {
            this._ship();
        }
    }

    _toWireFormat(event) {
        return {
            Timestamp: event.timestamp || new Date(),
            Level: LEVELS[event.level], // Missing is fine
            MessageTemplate: event.messageTemplate || "(No message provided)",
            Exception: event.exception, // Missing is fine
            Properties: event.properties // Missing is fine
        };
    }

    _eventTooLargeErrorEvent(event) {
        return {
            Timestamp: event.Timestamp,
            Level: event.Level,
            MessageTemplate: "(Event too large) {initial}...",
            Properties: {
                initial: event.MessageTemplate.substring(0, 12),
                sourceContext: "Seq Javascript Client",
                eventSizeLimit: this._eventSizeLimit
            }
        };
    }

    _reset(shipper) {
        if (this._activeShipper === shipper) {
            this._activeShipper = null;
            if (this._queue.length !== 0) {
                this._setTimer();
            }
        }
    }

    _ship() {
        if (this._queue.lenth === 0) {
            return Promise.resolve(false);
        }

        let wait = this._activeShipper || Promise.resolve(false);
        let shipper = this._activeShipper = wait
            .then(() => {
                let more = drained => {
                    if (drained) {
                        // If the queue was drained, let the timer
                        // push us forwards.
                        return true;
                    }
                    return this._sendBatch().then(d => more(d));
                }
                return this._sendBatch().then(drained => more(drained));
            })
            .then(() => this._reset(shipper), e => {
                this._onError(e);
                this._reset(shipper);
            });

        return shipper;
    }

    _sendBatch() {
        if (this._queue.length === 0) {
            return Promise.resolve(true);
        }

        let dequeued = this._dequeBatch();
        let drained = this._queue.length === 0;
        return this._post(dequeued.batch, dequeued.bytes).then(() => drained);
    }

    _dequeBatch() {
        var bytes = HEADER_FOOTER_BYTES;
        let batch = [];
        var i = 0;
        var delimSize = 0;
        while (i < this._queue.length) {
            let next = this._queue[i];
            let json = JSON.stringify(next);
            var jsonLen = Buffer.byteLength(json, 'utf8');
            if (jsonLen > this._eventSizeLimit) {
                this._onError("[seq] Event body is larger than " + this._eventSizeLimit + " bytes: " + json);
                this._queue[i] = next = this._eventTooLargeErrorEvent(next);
                json = JSON.stringify(next);
                jsonLen = Buffer.byteLength(json, 'utf8');
            }

            // Always try to send a batch of at least one event, even if the batch size is
            // tiny.
            if (i !== 0 && bytes + jsonLen + delimSize > this._batchSizeLimit) {
                break;
            }

            i = i + 1;
            bytes += jsonLen + delimSize;
            delimSize = 1; // ","
            batch.push(json);
        }

        this._queue.splice(0, i);
        return {batch, bytes};
    }

    _post(batch, bytes) {
        return new Promise((resolve, reject) => {
            var opts = {
                host: this._endpoint.hostname,
                port: this._endpoint.port,
                path: this._endpoint.path,
                protocol: this._endpoint.protocol,
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Content-Length': bytes
                }
            };

            if (this._apiKey) {
                opts.headers["X-Seq-ApiKey"] = self._apiKey;
            }

            let req = http.request(opts);

            req.on('response', res => {
                var httpErr = null;
                if (res.statusCode !== 200 && res.statusCode !== 201) {
                    httpErr = 'HTTP log shipping failed: ' + res.statusCode;
                }

                res.on('data', () => {});
                res.on('error', e => {
                    reject(e);
                });
                res.on('end', () => {
                    if (httpErr !== null) {
                        reject(httpErr);
                    } else {
                        resolve(true);
                    }
                });
            });

            req.on('error', e => {
                reject(e);
            });

            req.write(HEADER);
            var delim = "";
            for (var b = 0; b < batch.length; b++) {
                req.write(delim);
                delim = ",";
                req.write(batch[b]);
            }
            req.write(FOOTER);
            req.end();
        });
    }
}

module.exports = SeqLogger;
<commit_msg>Fixing typo<commit_after>"use strict";

let http = require('http');
let url = require('url');

const LEVELS = {
    "Verbose": "Verbose",
    "Debug": "Debug",
    "Information" : "Information",
    "Warning": "Warning",
    "Error": "Error",
    "Fatal": "Fatal"
};

const HEADER = "{Events:[";
const FOOTER = "]}";
const HEADER_FOOTER_BYTES = Buffer.byteLength(HEADER, 'utf8') + Buffer.byteLength(FOOTER, 'utf8');

class SeqLogger {
    constructor(config) {
        let dflt = {
            serverUrl: 'http://localhost:5341',
            apiKey: null,
            maxBatchingTime: 2000,
            eventSizeLimit: 256 * 1024,
            batchSizeLimit: 1024 * 1024,
            onError: e => { console.error("[seq]", e); }
        };
        let cfg = config || dflt;
        var serverUrl = cfg.serverUrl || dflt.serverUrl;
        if (!serverUrl.endsWith('/')) {
            serverUrl += '/';
        }
        this._endpoint = url.parse(serverUrl + 'api/events/raw');
        this._apiKey = cfg.apiKey || dflt.apiKey;
        this._maxBatchingTime = cfg.maxBatchingTime || dflt.maxBatchingTime;
        this._eventSizeLimit = cfg.eventSizeLimit || dflt.eventSizeLimit;
        this._batchSizeLimit = cfg.batchSizeLimit || dflt.batchSizeLimit;
        this._onError = cfg.onError || dflt.onError;
        this._queue = [];
        this._timer = null;
        this._closed = false;
        this._activeShipper = null;
    }

    // Flush events queued at the time of the call, and wait for pending writes to complete
    // regardless of configured batching/timers.
    flush() {
        return this._ship();
    }

    // Flush then close the logger, destroying timers and other resources.
    close() {
        if (this._closed) {
            throw new Error('The logger has already been closed.');
        }

        this._closed = true;
        this._clearTimer();

        return this.flush();
    }

    // Enqueue an event in Seq format.
    emit(event) {
        if (!event) {
            throw new Error('An event must be provided');
        }
        if (this._closed) {
            return;
        }
        let norm = this._toWireFormat(event);
        this._queue.push(norm);
        if (!this._activeShipper) {
            this._setTimer();
        }
    }

    _setTimer() {
        if (this._timer !== null) {
            return;
        }

        this._timer = setTimeout(() => {
            this._timer = null;
            this._onTimer();
        }, this._maxBatchingTime);
    }

    _clearTimer() {
        if (this._timer !== null) {
            clearTimeout(this._timer);
            this._timer = null;
        }
    }

    _onTimer() {
        if (!this._activeShipper) {
            this._ship();
        }
    }

    _toWireFormat(event) {
        return {
            Timestamp: event.timestamp || new Date(),
            Level: LEVELS[event.level], // Missing is fine
            MessageTemplate: event.messageTemplate || "(No message provided)",
            Exception: event.exception, // Missing is fine
            Properties: event.properties // Missing is fine
        };
    }

    _eventTooLargeErrorEvent(event) {
        return {
            Timestamp: event.Timestamp,
            Level: event.Level,
            MessageTemplate: "(Event too large) {initial}...",
            Properties: {
                initial: event.MessageTemplate.substring(0, 12),
                sourceContext: "Seq Javascript Client",
                eventSizeLimit: this._eventSizeLimit
            }
        };
    }

    _reset(shipper) {
        if (this._activeShipper === shipper) {
            this._activeShipper = null;
            if (this._queue.length !== 0) {
                this._setTimer();
            }
        }
    }

    _ship() {
        if (this._queue.length === 0) {
            return Promise.resolve(false);
        }

        let wait = this._activeShipper || Promise.resolve(false);
        let shipper = this._activeShipper = wait
            .then(() => {
                let more = drained => {
                    if (drained) {
                        // If the queue was drained, let the timer
                        // push us forwards.
                        return true;
                    }
                    return this._sendBatch().then(d => more(d));
                }
                return this._sendBatch().then(drained => more(drained));
            })
            .then(() => this._reset(shipper), e => {
                this._onError(e);
                this._reset(shipper);
            });

        return shipper;
    }

    _sendBatch() {
        if (this._queue.length === 0) {
            return Promise.resolve(true);
        }

        let dequeued = this._dequeBatch();
        let drained = this._queue.length === 0;
        return this._post(dequeued.batch, dequeued.bytes).then(() => drained);
    }

    _dequeBatch() {
        var bytes = HEADER_FOOTER_BYTES;
        let batch = [];
        var i = 0;
        var delimSize = 0;
        while (i < this._queue.length) {
            let next = this._queue[i];
            let json = JSON.stringify(next);
            var jsonLen = Buffer.byteLength(json, 'utf8');
            if (jsonLen > this._eventSizeLimit) {
                this._onError("[seq] Event body is larger than " + this._eventSizeLimit + " bytes: " + json);
                this._queue[i] = next = this._eventTooLargeErrorEvent(next);
                json = JSON.stringify(next);
                jsonLen = Buffer.byteLength(json, 'utf8');
            }

            // Always try to send a batch of at least one event, even if the batch size is
            // tiny.
            if (i !== 0 && bytes + jsonLen + delimSize > this._batchSizeLimit) {
                break;
            }

            i = i + 1;
            bytes += jsonLen + delimSize;
            delimSize = 1; // ","
            batch.push(json);
        }

        this._queue.splice(0, i);
        return {batch, bytes};
    }

    _post(batch, bytes) {
        return new Promise((resolve, reject) => {
            var opts = {
                host: this._endpoint.hostname,
                port: this._endpoint.port,
                path: this._endpoint.path,
                protocol: this._endpoint.protocol,
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Content-Length': bytes
                }
            };

            if (this._apiKey) {
                opts.headers["X-Seq-ApiKey"] = self._apiKey;
            }

            let req = http.request(opts);

            req.on('response', res => {
                var httpErr = null;
                if (res.statusCode !== 200 && res.statusCode !== 201) {
                    httpErr = 'HTTP log shipping failed: ' + res.statusCode;
                }

                res.on('data', () => {});
                res.on('error', e => {
                    reject(e);
                });
                res.on('end', () => {
                    if (httpErr !== null) {
                        reject(httpErr);
                    } else {
                        resolve(true);
                    }
                });
            });

            req.on('error', e => {
                reject(e);
            });

            req.write(HEADER);
            var delim = "";
            for (var b = 0; b < batch.length; b++) {
                req.write(delim);
                delim = ",";
                req.write(batch[b]);
            }
            req.write(FOOTER);
            req.end();
        });
    }
}

module.exports = SeqLogger;
<|endoftext|>


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

import {validator as v} from 'redux-router-querystring';

export const queryString = {
    recurrence: {
        validator: v.isIn(['single', 'daily', 'every']),
        stateField: 'filters.recurrence.type'
    },
    number: {
        validator: v.isInt({min: 1, max: 99}),
        sanitizer: v.toInt(),
        stateField: 'filters.recurrence.number'
    },
    interval: {
        validator: v.isIn(['day', 'week', 'month']),
        stateField: 'filters.recurrence.interval'
    },
    startDate: {
        validator: v.isDate(),
        stateField: 'filters.dates.startDate'
    },
    endDate: {
        validator: v.isDate(),
        stateField: 'filters.dates.endDate'
    },
    startTime: {
        validator: v.isTime(),
        stateField: 'filters.timeSlot.startTime'
    },
    endTime: {
        validator: v.isTime(),
        stateField: 'filters.timeSlot.endTime'
    },
    capacity: {
        validator: v.isInt({min: 1}),
        sanitizer: v.toInt(),
        stateField: 'filters.capacity'
    },
    building: {
        validator: v.isInt(),
        sanitizer: v.toInt(),
        stateField: 'filters.building'
    },
    floor: {
        stateField: 'filters.floor'
    },
    text: {
        stateField: 'filters.text'
    }
};

const _dtHandler = (prefix) => {
    return function({dates, timeSlot}) {
        const timePart = timeSlot[`${prefix}Time`];
        let datePart = dates[`${prefix}Date`];

        // single bookings have a 'null' endDate
        if (datePart === null && prefix === 'end') {
            datePart = dates['startDate'];
        }

        return moment(`${datePart} ${timePart}`, 'YYYY-MM-DD HH:mm').format('YYYY-MM-DD HH:mm');
    };
};

export const ajax = {
    repeat_frequency: {
        onlyIf: (data) => 'recurrence' in data,
        serializer: ({recurrence: {type, interval}}) => {
            if (type === 'single') {
                return 'NEVER';
            } else if (type === 'daily') {
                return 'DAY';
            } else {
                return {
                    daily: 'DAY',
                    week: 'WEEK',
                    month: 'MONTH'
                }[interval];
            }
        }
    },
    repeat_interval: {
        onlyIf: (data) => 'recurrence' in data,
        serializer: ({recurrence: {type, number}}) => {
            if (type === 'single') {
                return 0;
            } else if (type === 'daily') {
                return 1;
            } else {
                return number;
            }
        }
    },
    capacity: ({capacity}) => capacity,
    building: ({building}) => building,
    floor: ({floor}) => floor,
    text: ({text}) => text,
    start_dt: {
        onlyIf: (data) => 'dates' in data,
        serializer: _dtHandler('start')
    },
    end_dt: {
        onlyIf: (data) => 'dates' in data,
        serializer: _dtHandler('end')
    }
};
<commit_msg>Fix rooms list call with 'Invalid date'<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2018 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

import {validator as v} from 'redux-router-querystring';

export const queryString = {
    recurrence: {
        validator: v.isIn(['single', 'daily', 'every']),
        stateField: 'filters.recurrence.type'
    },
    number: {
        validator: v.isInt({min: 1, max: 99}),
        sanitizer: v.toInt(),
        stateField: 'filters.recurrence.number'
    },
    interval: {
        validator: v.isIn(['day', 'week', 'month']),
        stateField: 'filters.recurrence.interval'
    },
    startDate: {
        validator: v.isDate(),
        stateField: 'filters.dates.startDate'
    },
    endDate: {
        validator: v.isDate(),
        stateField: 'filters.dates.endDate'
    },
    startTime: {
        validator: v.isTime(),
        stateField: 'filters.timeSlot.startTime'
    },
    endTime: {
        validator: v.isTime(),
        stateField: 'filters.timeSlot.endTime'
    },
    capacity: {
        validator: v.isInt({min: 1}),
        sanitizer: v.toInt(),
        stateField: 'filters.capacity'
    },
    building: {
        validator: v.isInt(),
        sanitizer: v.toInt(),
        stateField: 'filters.building'
    },
    floor: {
        stateField: 'filters.floor'
    },
    text: {
        stateField: 'filters.text'
    }
};

const _dtHandler = (prefix) => {
    return function({dates, timeSlot}) {
        const timePart = timeSlot[`${prefix}Time`];
        let datePart = dates[`${prefix}Date`];

        // single bookings have a 'null' endDate
        if (datePart === null && prefix === 'end') {
            datePart = dates['startDate'];
        }

        return moment(`${datePart} ${timePart}`, 'YYYY-MM-DD HH:mm').format('YYYY-MM-DD HH:mm');
    };
};

export const ajax = {
    repeat_frequency: {
        onlyIf: (data) => 'recurrence' in data,
        serializer: ({recurrence: {type, interval}}) => {
            if (type === 'single') {
                return 'NEVER';
            } else if (type === 'daily') {
                return 'DAY';
            } else {
                return {
                    daily: 'DAY',
                    week: 'WEEK',
                    month: 'MONTH'
                }[interval];
            }
        }
    },
    repeat_interval: {
        onlyIf: (data) => 'recurrence' in data,
        serializer: ({recurrence: {type, number}}) => {
            if (type === 'single') {
                return 0;
            } else if (type === 'daily') {
                return 1;
            } else {
                return number;
            }
        }
    },
    capacity: ({capacity}) => capacity,
    building: ({building}) => building,
    floor: ({floor}) => floor,
    text: ({text}) => text,
    start_dt: {
        onlyIf: (data) => data.dates && data.dates.startDate,
        serializer: _dtHandler('start')
    },
    end_dt: {
        onlyIf: (data) => data.dates && data.dates.endDate,
        serializer: _dtHandler('end')
    }
};
<|endoftext|>


<commit_before>/***************************************************************************
 * dumpItems.js : Methods for dumping query results to lists and selectors
 ***************************************************************************/

/*
 * Authors:
 *  Jose Dapena Paz <jdapena@igalia.com>
 *
 * Copyright (c) 2012, Igalia, S.L.
 * All rights reserved.
 *
 * See license.js
 */

function dumpAccountInAccountsList (account, parent)
{
    li = document.createElement("li");
    li.setAttribute('id', 'account-item-'+account.id);
    li.setAttribute('data-role', 'fieldcontain');
    a = document.createElement("a");
    a.setAttribute('href', '#page-folders?account='+account.id);
    a.accountId = account.id;
    $(a).click(function () {
	globalStatus.currentAccount = this.accountId;
	globalStatus.currentFolder = null;
	globalStatus.currentMessage = null;
	fillFoldersList(this.accountId);
	return true;
    });

    h3 = document.createElement("h3");
    $(h3).text(account.displayName);
    p = document.createElement("p");
    if (account.isDefault)
	$(p).text(account.emailAddress + " (default)")
    else
	$(p).text(account.emailAddress);
    countSpan = document.createElement("span");
    countSpan.className += " ui-li-count account-count";
    $(countSpan).hide();
    $(countSpan).text(0);
    a.appendChild(h3);
    a.appendChild(p);
    a.appendChild(countSpan);
    li.appendChild(a);
    $(parent).append(li);
}

function dumpAddAccountInAccountsList (parent)
{
    li = document.createElement ("li");
    a = document.createElement ("a");
    a.setAttribute("href", "#create-account");
    a.setAttribute("id", "add-account-button");
    a.setAttribute("data-role", "button");
    a.setAttribute("data-icon", "plus");
    a.className += "account-item";
    a.innerText = "Add account";

    li.appendChild(a);
    $(parent).append(li);
}

function dumpAccountOptionInComposerFrom (account, parent)
{
    li = document.createElement("li");
    composerFromOption=document.createElement("option");
    composerFromOption.setAttribute("id", "composer-from-"+account.id);
    composerFromOption.setAttribute('value', account.id);
    composerFromOption.account = account.id;
    if (account.isDefault)
	composerFromOption.setAttribute("selected", "true");
    $(composerFromOption).text(account.emailAddress);
    $(parent).append(composerFromOption);
}

function dumpMessageAsViewHeader (message, parent)
{
    outgoing = message.draft || getCurrentFolder().isSent;
    if (outgoing)
	$(parent+" #recipient").text(addressesGetDisplay (message.to));
    else
	$(parent+" #recipient").text(addressGetDisplay (message.from));
    $(parent+" #subject").text(message.subject);
    $(parent+" #date").text(formatTime (message.dateReceived));
}

function dumpAddressDetail(display, email, parent)
{
    console.log("Dumping address [display:"+display+"] [email:"+email+"]");
    newLi = document.createElement('li');
    newLi.setAttribute('data-role', 'fieldcontain');
    newHeader = document.createElement('h3');
    if (display && display.length > 0) {
	$(newHeader).text(display);
	newP = document.createElement('p');
	$(newP).text(email);
	$(newLi).append(newHeader);
	$(newLi).append(newP);
    } else {
    	$(newHeader).text(email);
	$(newLi).append(newHeader);
    }
    $(parent).append(newLi);
}

function dumpDetail(fieldName, fieldValue, parent)
{
    newLi = document.createElement('li');
    newLi.setAttribute('data-role', 'fieldcontain');
    newP = document.createElement('p');
    $(newP).text(fieldName);
    newHeader = document.createElement('h3');
    $(newHeader).text(fieldValue);
    newLi.appendChild(newP);
    newLi.appendChild(newHeader);
    $(parent).append(newLi);
}

function dumpMessageAsDetails (message, parent)
{
    $(parent).empty();

    if (message.from && message.from.length > 0) {
    	$(parent).append("
From:
");
    	for (i in message.from) {
	    dumpAddressDetail (message.from[i].displayName, message.from[i].emailAddress, parent);
    	}
    }
    if (message.to && message.to.length > 0) {
    	$(parent).append("
To:
");
    	for (i in message.to) {
	    dumpAddressDetail (message.to[i].displayName, message.to[i].emailAddress, parent);
    	}
    }
    if (message.cc && message.cc.length > 0) {
    	$(parent).append("
Cc:
");
    	for (i in message.cc) {
	    dumpAddressDetail (message.cc[i].displayName, message.cc[i].emailAddress, parent);
    	}
    }
    if (message.bcc && message.bcc.length > 0) {
    	$(parent).append("
Bcc:
");
    	for (i in message.bcc) {
	    dumpAddressDetail (message.bcc[i].displayName, message.bcc[i].emailAddress, parent);
    	}
    }

    $(parent).append("
Details
");
    dumpDetail ('Subject:', message.subject, parent);
    if (message.mlist)
	dumpDetail ('Mailing list:', message.mlist, parent);
    console.log($("#page-message-details").html());
}

function dumpFolderInFolderList (accountId, folderFullName, folder, parent)
{
    li = document.createElement("li");
    li.setAttribute('id', 'folder-item-'+accountId+'-'+folderFullName);
    li.setAttribute('data-role', 'fieldcontain');

    h3 = document.createElement("h3");
    if ('fullDisplayName' in folder)
	$(h3).text(folder.fullDisplayName);
    else
	$(h3).text(folder.displayName);

    if (!folder.noSelect) {
	a = document.createElement("a");
	a.accountId=accountId;
	a.folderFullName=folderFullName;
	a.displayName = folder.displayName;
	a.setAttribute('href', '#page-messages');
	$(a).click(function () {
	    if (globalStatus.currentAccount != this.accountId || globalStatus.currentFolder != this.folderFullName) {
		globalStatus.currentAccount = this.accountId;
		globalStatus.currentFolder = this.folderFullName;
		globalStatus.currentmessage = null;
		globalStatus.newestUid = null;
		globalStatus.oldestUid = null;
		$("#page-messages-title").text(this.displayName);
		$("#page-message-title").text(this.displayName);
		$("#page-messages #messages-list").html("");
		showMessages(this.accountId, this.folderFullName, false);
	    } else {
		$("#messages-list-get-more-list").show();
		$("#messages-list-getting-more-list").hide();
	    }
	    return true;
	});
    }

    if ('unreadCount' in folder && folder.unreadCount > 0) {
	countSpan = document.createElement("span");
	countSpan.className += " ui-li-count";
	$(countSpan).text(folder.unreadCount);
	a.appendChild(countSpan);
	unreadCount = folder.unreadCount;
    }

    if (folder.noSelect) {
	li.appendChild(h3);
    } else {
	a.appendChild(h3);
	li.appendChild(a);
    }
    $(parent).append(li);
}

function dumpMessageInMessagesList (message, isNew, parent)
{
    li = document.createElement("li");
    $(li).attr("id", "message-item-"+message.uid);
    li.setAttribute('data-role', 'fieldcontain');
    if (message.unread)
	li.className += " iwk-unread-item";
    else
	li.className += " iwk-read-item";
    a = document.createElement("a");
    a.className += "iwk-message-item-link";
    a.setAttribute("href", "#page-message");
    a.accountId = globalStatus.currentAccount;
    a.folderFullName = globalStatus.currentFolder
    a.messageUid = message.uid;
    a.message = message;
    $(a).click(function () {
	globalStatus.currentAccount = this.accountId;
	globalStatus.currentFolder = this.folderFullName
	globalStatus.currentMessage = this.messageUid;
	showMessage(this.message);
	return true;
    });
    h3 = document.createElement("h3");
    $(h3).text(message.subject);
    p = document.createElement("p");
    outgoing = message.draft || getCurrentFolder().isSent;
    if (outgoing) {
	$(p).text(addressesGetDisplay(message.to));
    } else {
	$(p).text(addressGetDisplay(message.from));
    }
    date = document.createElement("p");
    date.className += "ui-li-aside";
    $(date).text(formatTime(message.dateReceived));
    a.appendChild(h3);
    a.appendChild(p);
    a.appendChild(date);
    li.appendChild(a);

    if (isNew)
	$(parent).prepend(li);
    else
	$(parent).append(li);
}<commit_msg>Fix updating message details.<commit_after>/***************************************************************************
 * dumpItems.js : Methods for dumping query results to lists and selectors
 ***************************************************************************/

/*
 * Authors:
 *  Jose Dapena Paz <jdapena@igalia.com>
 *
 * Copyright (c) 2012, Igalia, S.L.
 * All rights reserved.
 *
 * See license.js
 */

function dumpAccountInAccountsList (account, parent)
{
    li = document.createElement("li");
    li.setAttribute('id', 'account-item-'+account.id);
    li.setAttribute('data-role', 'fieldcontain');
    a = document.createElement("a");
    a.setAttribute('href', '#page-folders?account='+account.id);
    a.accountId = account.id;
    $(a).click(function () {
	globalStatus.currentAccount = this.accountId;
	globalStatus.currentFolder = null;
	globalStatus.currentMessage = null;
	fillFoldersList(this.accountId);
	return true;
    });

    h3 = document.createElement("h3");
    $(h3).text(account.displayName);
    p = document.createElement("p");
    if (account.isDefault)
	$(p).text(account.emailAddress + " (default)")
    else
	$(p).text(account.emailAddress);
    countSpan = document.createElement("span");
    countSpan.className += " ui-li-count account-count";
    $(countSpan).hide();
    $(countSpan).text(0);
    a.appendChild(h3);
    a.appendChild(p);
    a.appendChild(countSpan);
    li.appendChild(a);
    $(parent).append(li);
}

function dumpAddAccountInAccountsList (parent)
{
    li = document.createElement ("li");
    a = document.createElement ("a");
    a.setAttribute("href", "#create-account");
    a.setAttribute("id", "add-account-button");
    a.setAttribute("data-role", "button");
    a.setAttribute("data-icon", "plus");
    a.className += "account-item";
    a.innerText = "Add account";

    li.appendChild(a);
    $(parent).append(li);
}

function dumpAccountOptionInComposerFrom (account, parent)
{
    li = document.createElement("li");
    composerFromOption=document.createElement("option");
    composerFromOption.setAttribute("id", "composer-from-"+account.id);
    composerFromOption.setAttribute('value', account.id);
    composerFromOption.account = account.id;
    if (account.isDefault)
	composerFromOption.setAttribute("selected", "true");
    $(composerFromOption).text(account.emailAddress);
    $(parent).append(composerFromOption);
}

function dumpMessageAsViewHeader (message, parent)
{
    outgoing = message.draft || getCurrentFolder().isSent;
    if (outgoing)
	$(parent+" #recipient").text(addressesGetDisplay (message.to));
    else
	$(parent+" #recipient").text(addressGetDisplay (message.from));
    $(parent+" #subject").text(message.subject);
    $(parent+" #date").text(formatTime (message.dateReceived));
}

function dumpAddressDetail(display, email, parent)
{
    console.log("Dumping address [display:"+display+"] [email:"+email+"]");
    newLi = document.createElement('li');
    newLi.setAttribute('data-role', 'fieldcontain');
    newHeader = document.createElement('h3');
    if (display && display.length > 0) {
	$(newHeader).text(display);
	newP = document.createElement('p');
	$(newP).text(email);
	$(newLi).append(newHeader);
	$(newLi).append(newP);
    } else {
    	$(newHeader).text(email);
	$(newLi).append(newHeader);
    }
    $(parent).append(newLi);
}

function dumpDetail(fieldName, fieldValue, parent)
{
    newLi = document.createElement('li');
    newLi.setAttribute('data-role', 'fieldcontain');
    newP = document.createElement('p');
    $(newP).text(fieldName);
    newHeader = document.createElement('h3');
    $(newHeader).text(fieldValue);
    newLi.appendChild(newP);
    newLi.appendChild(newHeader);
    $(parent).append(newLi);
}

function dumpMessageAsDetails (message, parent)
{
    $(parent).empty();

    if (message.from && message.from.length > 0) {
    	$(parent).append("
From:
");
    	for (i in message.from) {
	    dumpAddressDetail (message.from[i].displayName, message.from[i].emailAddress, parent);
    	}
    }
    if (message.to && message.to.length > 0) {
    	$(parent).append("
To:
");
    	for (i in message.to) {
	    dumpAddressDetail (message.to[i].displayName, message.to[i].emailAddress, parent);
    	}
    }
    if (message.cc && message.cc.length > 0) {
    	$(parent).append("
Cc:
");
    	for (i in message.cc) {
	    dumpAddressDetail (message.cc[i].displayName, message.cc[i].emailAddress, parent);
    	}
    }
    if (message.bcc && message.bcc.length > 0) {
    	$(parent).append("
Bcc:
");
    	for (i in message.bcc) {
	    dumpAddressDetail (message.bcc[i].displayName, message.bcc[i].emailAddress, parent);
    	}
    }

    $(parent).append("
Details
");
    dumpDetail ('Subject:', message.subject, parent);
    if (message.mlist)
	dumpDetail ('Mailing list:', message.mlist, parent);
    console.log($("#page-message-details").html());

    if ($(parent).hasClass("ui-listview")) {
	$(parent).listview("refresh");
    }
}

function dumpFolderInFolderList (accountId, folderFullName, folder, parent)
{
    li = document.createElement("li");
    li.setAttribute('id', 'folder-item-'+accountId+'-'+folderFullName);
    li.setAttribute('data-role', 'fieldcontain');

    h3 = document.createElement("h3");
    if ('fullDisplayName' in folder)
	$(h3).text(folder.fullDisplayName);
    else
	$(h3).text(folder.displayName);

    if (!folder.noSelect) {
	a = document.createElement("a");
	a.accountId=accountId;
	a.folderFullName=folderFullName;
	a.displayName = folder.displayName;
	a.setAttribute('href', '#page-messages');
	$(a).click(function () {
	    if (globalStatus.currentAccount != this.accountId || globalStatus.currentFolder != this.folderFullName) {
		globalStatus.currentAccount = this.accountId;
		globalStatus.currentFolder = this.folderFullName;
		globalStatus.currentmessage = null;
		globalStatus.newestUid = null;
		globalStatus.oldestUid = null;
		$("#page-messages-title").text(this.displayName);
		$("#page-message-title").text(this.displayName);
		$("#page-messages #messages-list").html("");
		showMessages(this.accountId, this.folderFullName, false);
	    } else {
		$("#messages-list-get-more-list").show();
		$("#messages-list-getting-more-list").hide();
	    }
	    return true;
	});
    }

    if ('unreadCount' in folder && folder.unreadCount > 0) {
	countSpan = document.createElement("span");
	countSpan.className += " ui-li-count";
	$(countSpan).text(folder.unreadCount);
	a.appendChild(countSpan);
	unreadCount = folder.unreadCount;
    }

    if (folder.noSelect) {
	li.appendChild(h3);
    } else {
	a.appendChild(h3);
	li.appendChild(a);
    }
    $(parent).append(li);
}

function dumpMessageInMessagesList (message, isNew, parent)
{
    li = document.createElement("li");
    $(li).attr("id", "message-item-"+message.uid);
    li.setAttribute('data-role', 'fieldcontain');
    if (message.unread)
	li.className += " iwk-unread-item";
    else
	li.className += " iwk-read-item";
    a = document.createElement("a");
    a.className += "iwk-message-item-link";
    a.setAttribute("href", "#page-message");
    a.accountId = globalStatus.currentAccount;
    a.folderFullName = globalStatus.currentFolder
    a.messageUid = message.uid;
    a.message = message;
    $(a).click(function () {
	globalStatus.currentAccount = this.accountId;
	globalStatus.currentFolder = this.folderFullName
	globalStatus.currentMessage = this.messageUid;
	showMessage(this.message);
	return true;
    });
    h3 = document.createElement("h3");
    $(h3).text(message.subject);
    p = document.createElement("p");
    outgoing = message.draft || getCurrentFolder().isSent;
    if (outgoing) {
	$(p).text(addressesGetDisplay(message.to));
    } else {
	$(p).text(addressGetDisplay(message.from));
    }
    date = document.createElement("p");
    date.className += "ui-li-aside";
    $(date).text(formatTime(message.dateReceived));
    a.appendChild(h3);
    a.appendChild(p);
    a.appendChild(date);
    li.appendChild(a);

    if (isNew)
	$(parent).prepend(li);
    else
	$(parent).append(li);
}<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-2017 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true, mocha: true, expr: true */

;(function (window, $, undefined) {

    'use strict';

    var expect = window.chai.expect;
    var sinon = window.sinon;
    var kendo = window.kendo;
    var ui = kendo.ui;
    var Markdown = ui.Markdown;
    var CHANGE = 'change';
    var FIXTURES = '#fixtures';
    var MARKDOWN1 = '

';
    var MARKDOWN2 = '

';

    describe('kidoju.widgets.markdown', function () {

        // TODO

    });

}(this, jQuery));
<commit_msg>Added skeleton for markdown https://github.com/kidoju/Kidoju-Widgets/issues/86<commit_after>/**
 * Copyright (c) 2013-2017 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true, mocha: true, expr: true */

;(function (window, $, undefined) {

    'use strict';

    var expect = window.chai.expect;
    var sinon = window.sinon;
    var kendo = window.kendo;
    var ui = kendo.ui;
    var Markdown = ui.Markdown;
    var FIXTURES = '#fixtures';
    var MARKDOWN1 = '

';
    var MARKDOWN2 = '

';

    describe('kidoju.widgets.markdown', function () {

        before(function () {
            if (window.__karma__ && $(FIXTURES).length === 0) {
                $('body').append('

');
            }
        });

        describe('Availability', function () {

            it('requirements', function () {
                expect($).not.to.be.undefined;
                expect(kendo).not.to.be.undefined;
                expect(kendo.version).to.be.a('string');
                expect($.fn.kendoMarkdown).to.be.an.instanceof(Function);
            });

        });

        describe('Initialization', function () {

            it('from code', function () {
                var element = $(MARKDOWN1).appendTo(FIXTURES);
                var markDown = element.kendoMarkdown().data('kendoMarkdown');
                expect(markDown).to.be.an.instanceof(Markdown);
                // expect(element).to.have.class('k-widget');
                expect(element).to.have.class('kj-markdown');
            });

            it('from code with options', function () {
                var element = $(MARKDOWN1).appendTo(FIXTURES);
                var options = {

                };
                var markDown = element.kendoMarkdown().data('kendoMarkdown');
                expect(markDown).to.be.an.instanceof(Markdown);
                // expect(element).to.have.class('k-widget');
                expect(element).to.have.class('kj-markdown');
            });

            it('from markup', function () {
                var element = $(MARKDOWN2).appendTo(FIXTURES);
                kendo.init(FIXTURES);
                var markDown = element.data('kendoMarkdown');
                expect(markDown).to.be.an.instanceof(Markdown);
                // expect(element).to.have.class('k-widget');
                expect(element).to.have.class('kj-markdown');
            });

            xit('from markup with attributes', function () {

            });

            afterEach(function () {
                var fixtures = $(FIXTURES);
                kendo.destroy(fixtures);
                fixtures.find('*').off();
                fixtures.empty();
            });

        });

        describe('Methods', function () {

            var element;
            var markDown;
            var options = {};

            beforeEach(function () {
                element = $(MARKDOWN1).appendTo(FIXTURES);
                markDown = element.kendoMarkdown(options).data('kendoMarkdown');
            });

            xit('value', function (done) {
                expect(markDown).to.be.an.instanceof(Markdown);
            });

            xit('setOptions', function () {

            });

            xit('destroy', function () {
                expect(markDown).to.be.an.instanceof(Markdown);
                markDown.destroy();
                expect(markDown.element).to.be.empty;
            });

            afterEach(function () {
                var fixtures = $(FIXTURES);
                kendo.destroy(fixtures);
                fixtures.find('*').off();
                fixtures.empty();
            });

        });

        describe('MVVM (and UI interactions)', function () {

            var element;
            var markDown;
            var options = {};
            var viewModel;
            var change;
            var destroy;

            beforeEach(function () {
                element = $(MARKDOWN1).appendTo(FIXTURES);
                markDown = element.kendoMarkdown(options).data('kendoMarkdown');
                viewModel = kendo.observable({
                    // TODO
                });
                change = sinon.spy();
                destroy = sinon.spy();
            });

            xit('TODO', function () {

            });

            afterEach(function () {
                var fixtures = $(FIXTURES);
                kendo.destroy(fixtures);
                fixtures.find('*').off();
                fixtures.empty();
            });

        });

        describe('Events', function () {

            var element;
            var markDown;
            var options = {};
            var event;

            beforeEach(function () {
                element = $(MARKDOWN1).appendTo(FIXTURES);
                markDown = element.kendoMarkdown(options).data('kendoMarkdown');
                event = sinon.spy();
            });

            xit('TODO', function () {

            });

            afterEach(function () {
                var fixtures = $(FIXTURES);
                kendo.destroy(fixtures);
                fixtures.find('*').off();
                fixtures.empty();
            });

        });
    });

}(this, jQuery));
<|endoftext|>


<commit_before>'use strict';

/*global angular, cytoscape, $*/

angular.module('app').service('graphService', function(tracingService, $mdDialog) {

  var graph = this;

  var _cy;
  var _data;
  var _mergeDeliveries = false;
  var _nodeSize = 10;
  var _fontSize = 10;

  graph.init = function(data) {
    for (let s of data.stations) {
      s.data.size = _nodeSize;
    }

    _data = data;

    if (_cy === undefined) {
      _cy = cytoscape({
        container: $('#graph')[0],

        elements: createElements(),

        layout: {
          name: 'random'
        },

        style: createStyle(),
        minZoom: 0.01,
        maxZoom: 10,
        wheelSensitivity: 0.5,
      });
    }
    else {
      var json = _cy.json();

      _cy = cytoscape({
        container: $('#graph')[0],

        elements: createElements(),

        layout: {
          name: 'preset',
          positions: function(node) {
            return json.elements.nodes.find(function(n) {
              return n.data.id === node.id();
            }).position;
          },
          zoom: json.zoom,
          pan: json.pan
        },

        style: createStyle(),
        minZoom: json.minZoom,
        maxZoom: json.maxZoom,
        wheelSensitivity: json.wheelSensitivity,
      });
    }

    _cy.on('zoom', function(event) {
      graph.setFontSize(_fontSize);
    });
    _cy.panzoom();
    _cy.cxtmenu(contextMenu);
    _cy.cxtmenu(stationContextMenu);
    _cy.cxtmenu(deliveryContextMenu);
    tracingService.init(data);
  };

  graph.setMergeDeliveries = function(mergeDeliveries) {
    _mergeDeliveries = mergeDeliveries;
    updateEdges();
  };

  graph.setNodeSize = function(nodeSize) {
    _nodeSize = nodeSize;

    for (let s of _data.stations) {
      s.data.size = s.data.score !== undefined ? (1 + s.data.score) * nodeSize : nodeSize;
    }

    repaint();
  };

  graph.setFontSize = function(fontSize) {
    _fontSize = fontSize;

    _cy.nodes().css({
      'font-size': Math.max(fontSize / _cy.zoom(), fontSize)
    });
  };

  function repaint() {
    if (_mergeDeliveries) {
      updateEdges();
      _cy.nodes().data('update', true);
    }
    else {
      _cy.elements().data('update', true);
    }
  }

  function updateEdges() {
    var edges = createElements().edges;

    for (let e of edges) {
      e.group = "edges";
    }

    _cy.edges().remove();
    _cy.add(edges);
  }

  function createElements() {
    if (_mergeDeliveries) {
      var sourceTargetMap = new Map();

      for (let d of _data.deliveries) {
        var key = d.data.source + '->' + d.data.target;
        var value = sourceTargetMap.get(key);

        sourceTargetMap.set(key, value !== undefined ? value.concat(d) : [d]);
      }

      var mergedDeliveries = [];

      for (let value of sourceTargetMap.values()) {
        var source = value[0].data.source;
        var target = value[0].data.target;

        mergedDeliveries.push({
          data: {
            id: source + '->' + target,
            source: source,
            target: target,
            backward: value.find(function(d) {
              return d.data.backward === true;
            }) !== undefined,
            forward: value.find(function(d) {
              return d.data.forward === true;
            }) !== undefined
          }
        });
      }

      return {
        nodes: _data.stations,
        edges: mergedDeliveries
      };
    }
    else {
      return {
        nodes: _data.stations,
        edges: _data.deliveries
      };
    }
  }

  function createStyle() {
    var style = cytoscape.stylesheet()
      .selector('node')
      .css({
        'content': 'data(name)',
        'height': 'data(size)',
        'width': 'data(size)',
        'background-color': '#FFFFFF',
        'border-width': 3,
        'border-color': '#000000',
        'text-valign': 'bottom',
        'text-halign': 'right',
        'color': '#000000'
      })
      .selector('edge')
      .css({
        'target-arrow-shape': 'triangle',
        'width': 6,
        'line-color': '#000000',
        'target-arrow-color': '#FF0000',
        'curve-style': 'bezier'
      })
      .selector('node:selected')
      .css({
        'background-color': '#8080FF',
        'border-width': 6,
        'border-color': '#0000FF',
        'color': '#0000FF'
      })
      .selector('edge:selected')
      .css({
        'width': 12
      });

    var nodeProps = {
      'forward': [0, 255, 0],
      'backward': [0, 128, 128],
      'observed': [0, 0, 255],
      'outbreak': [255, 0, 0]
    };

    var edgeProps = {
      'forward': [0, 255, 0],
      'backward': [0, 128, 128],
      'observed': [0, 0, 255],
    };

    for (let combination of getAllCombination(Object.keys(nodeProps))) {
      var s = [];
      var c1 = [];
      var c2 = [];

      for (let prop of combination) {
        s.push('[?' + prop + ']');
        c1.push(nodeProps[prop]);
        c2.push(mix(nodeProps[prop], [0, 0, 255]));
      }

      style = style.selector('node' + s.join('')).css(createNodeBackground(c1));
      style = style.selector('node:selected' + s.join('')).css(createNodeBackground(c2));
    }

    for (let prop of Object.keys(edgeProps)) {
      style = style.selector('edge[?' + prop + ']').css(createEdgeColor(edgeProps[prop]));
    }

    return style;
  }

  function getAllCombination(values) {
    var n = Math.pow(2, values.length);
    var combinations = [];

    for (let i = 1; i < n; i++) {
      var bits = i.toString(2).split('').reverse().join('');
      var combination = [];

      for (let j = 0; j < values.length; j++) {
        if (bits[j] === '1') {
          combination.push(values[j]);
        }
      }

      combinations.push(combination);
    }

    combinations.sort(function(c1, c2) {
      return c1.length - c2.length;
    });

    return combinations;
  }

  function createNodeBackground(colors) {
    if (colors.length == 1) {
      return {
        'background-color': toRGB(colors[0])
      };
    }

    var css = {};

    for (var i = 0; i < colors.length; i++) {
      css['pie-' + (i + 1) + '-background-color'] = toRGB(colors[i]);
      css['pie-' + (i + 1) + '-background-size'] = 100 / colors.length;
    }

    return css;
  }

  function createEdgeColor(color) {
    return {
      'line-color': toRGB(color)
    };
  }

  function mix(color1, color2) {
    var r = Math.round((color1[0] + color2[0]) / 2);
    var g = Math.round((color1[1] + color2[1]) / 2);
    var b = Math.round((color1[2] + color2[2]) / 2);

    return [r, g, b];
  }

  function toRGB(color) {
    return 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
  }

  var contextMenu = {
    selector: 'core',
    commands: [{
      content: 'Apply Layout',
      select: function() {
        $mdDialog.show({
          controller: function($scope) {
            $scope.select = function(layout) {
              $mdDialog.hide(layout);
            };
          },
          template: `
            <md-dialog aria-label="Apply Layout">
              <md-toolbar><dialog-toolbar title="Apply Layout"></dialog-toolbar></md-toolbar>
              <md-dialog-content><layout-select on-select="select(layout)"></layout-select></md-dialog-content>
            </md-dialog>
          `,
          parent: angular.element(document.body),
          clickOutsideToClose: true
        }).then(function(layout) {
          _cy.layout(layout);
        });
      }
    }, {
      content: 'Zoom to Graph',
      select: function() {
        _cy.fit();
      }
    }, {
      content: 'Clear Trace',
      select: function() {
        tracingService.clearTrace();
        repaint();
      }
    }]
  };

  var stationContextMenu = {
    selector: 'node',
    commands: [{
      content: 'Show Forward Trace',
      select: function(station) {
        tracingService.clearTrace();
        tracingService.showStationForwardTrace(station.id());
        repaint();
      }
    }, {
      content: 'Show Backward Trace',
      select: function(station) {
        tracingService.clearTrace();
        tracingService.showStationBackwardTrace(station.id());
        repaint();
      }
    }, {
      content: 'Show Whole Trace',
      select: function(station) {
        tracingService.clearTrace();
        tracingService.showStationForwardTrace(station.id());
        tracingService.showStationBackwardTrace(station.id());
        repaint();
      }
    }, {
      content: 'Mark/Unmark as Outbreak',
      select: function(station) {
        tracingService.toggleOutbreakStation(station.id());
        graph.setNodeSize(_nodeSize);
        repaint();
      }
    }]
  };

  var deliveryContextMenu = {
    selector: 'edge',
    commands: [{
      content: 'Show Forward Trace',
      select: function(delivery) {
        tracingService.clearTrace();
        tracingService.showDeliveryForwardTrace(delivery.id());
        repaint();
      }
    }, {
      content: 'Show Backward Trace',
      select: function(delivery) {
        tracingService.clearTrace();
        tracingService.showDeliveryBackwardTrace(delivery.id());
        repaint();
      }
    }, {
      content: 'Show Whole Trace',
      select: function(delivery) {
        tracingService.clearTrace();
        tracingService.showDeliveryForwardTrace(delivery.id());
        tracingService.showDeliveryBackwardTrace(delivery.id());
        repaint();
      }
    }]
  };
});
<commit_msg>node size is now based on score<commit_after>'use strict';

/*global angular, cytoscape, $*/

angular.module('app').service('graphService', function(tracingService, $mdDialog) {

  var graph = this;

  var _cy;
  var _data;
  var _mergeDeliveries = false;
  var _nodeSize = 10;
  var _fontSize = 10;

  graph.init = function(data) {
    for (let s of data.stations) {
      s.data.size = _nodeSize;
    }

    _data = data;

    if (_cy === undefined) {
      _cy = cytoscape({
        container: $('#graph')[0],

        elements: createElements(),

        layout: {
          name: 'random'
        },

        style: createStyle(),
        minZoom: 0.01,
        maxZoom: 10,
        wheelSensitivity: 0.5,
      });
    }
    else {
      var json = _cy.json();

      _cy = cytoscape({
        container: $('#graph')[0],

        elements: createElements(),

        layout: {
          name: 'preset',
          positions: function(node) {
            return json.elements.nodes.find(function(n) {
              return n.data.id === node.id();
            }).position;
          },
          zoom: json.zoom,
          pan: json.pan
        },

        style: createStyle(),
        minZoom: json.minZoom,
        maxZoom: json.maxZoom,
        wheelSensitivity: json.wheelSensitivity,
      });
    }

    _cy.on('zoom', function(event) {
      graph.setFontSize(_fontSize);
    });
    _cy.panzoom();
    _cy.cxtmenu(contextMenu);
    _cy.cxtmenu(stationContextMenu);
    _cy.cxtmenu(deliveryContextMenu);
    tracingService.init(data);
  };

  graph.setMergeDeliveries = function(mergeDeliveries) {
    _mergeDeliveries = mergeDeliveries;
    updateEdges();
  };

  graph.setNodeSize = function(nodeSize) {
    _nodeSize = nodeSize;

    for (let s of _data.stations) {
      s.data.size = s.data.score !== undefined ? 0.5 * (1 + s.data.score) * nodeSize : nodeSize;
    }

    repaint();
  };

  graph.setFontSize = function(fontSize) {
    _fontSize = fontSize;

    _cy.nodes().css({
      'font-size': Math.max(fontSize / _cy.zoom(), fontSize)
    });
  };

  function repaint() {
    if (_mergeDeliveries) {
      updateEdges();
      _cy.nodes().data('update', true);
    }
    else {
      _cy.elements().data('update', true);
    }
  }

  function updateEdges() {
    var edges = createElements().edges;

    for (let e of edges) {
      e.group = "edges";
    }

    _cy.edges().remove();
    _cy.add(edges);
  }

  function createElements() {
    if (_mergeDeliveries) {
      var sourceTargetMap = new Map();

      for (let d of _data.deliveries) {
        var key = d.data.source + '->' + d.data.target;
        var value = sourceTargetMap.get(key);

        sourceTargetMap.set(key, value !== undefined ? value.concat(d) : [d]);
      }

      var mergedDeliveries = [];

      for (let value of sourceTargetMap.values()) {
        var source = value[0].data.source;
        var target = value[0].data.target;

        mergedDeliveries.push({
          data: {
            id: source + '->' + target,
            source: source,
            target: target,
            backward: value.find(function(d) {
              return d.data.backward === true;
            }) !== undefined,
            forward: value.find(function(d) {
              return d.data.forward === true;
            }) !== undefined
          }
        });
      }

      return {
        nodes: _data.stations,
        edges: mergedDeliveries
      };
    }
    else {
      return {
        nodes: _data.stations,
        edges: _data.deliveries
      };
    }
  }

  function createStyle() {
    var style = cytoscape.stylesheet()
      .selector('node')
      .css({
        'content': 'data(name)',
        'height': 'data(size)',
        'width': 'data(size)',
        'background-color': '#FFFFFF',
        'border-width': 3,
        'border-color': '#000000',
        'text-valign': 'bottom',
        'text-halign': 'right',
        'color': '#000000'
      })
      .selector('edge')
      .css({
        'target-arrow-shape': 'triangle',
        'width': 6,
        'line-color': '#000000',
        'target-arrow-color': '#FF0000',
        'curve-style': 'bezier'
      })
      .selector('node:selected')
      .css({
        'background-color': '#8080FF',
        'border-width': 6,
        'border-color': '#0000FF',
        'color': '#0000FF'
      })
      .selector('edge:selected')
      .css({
        'width': 12
      });

    var nodeProps = {
      'forward': [0, 255, 0],
      'backward': [0, 128, 128],
      'observed': [0, 0, 255],
      'outbreak': [255, 0, 0]
    };

    var edgeProps = {
      'forward': [0, 255, 0],
      'backward': [0, 128, 128],
      'observed': [0, 0, 255],
    };

    for (let combination of getAllCombination(Object.keys(nodeProps))) {
      var s = [];
      var c1 = [];
      var c2 = [];

      for (let prop of combination) {
        s.push('[?' + prop + ']');
        c1.push(nodeProps[prop]);
        c2.push(mix(nodeProps[prop], [0, 0, 255]));
      }

      style = style.selector('node' + s.join('')).css(createNodeBackground(c1));
      style = style.selector('node:selected' + s.join('')).css(createNodeBackground(c2));
    }

    for (let prop of Object.keys(edgeProps)) {
      style = style.selector('edge[?' + prop + ']').css(createEdgeColor(edgeProps[prop]));
    }

    return style;
  }

  function getAllCombination(values) {
    var n = Math.pow(2, values.length);
    var combinations = [];

    for (let i = 1; i < n; i++) {
      var bits = i.toString(2).split('').reverse().join('');
      var combination = [];

      for (let j = 0; j < values.length; j++) {
        if (bits[j] === '1') {
          combination.push(values[j]);
        }
      }

      combinations.push(combination);
    }

    combinations.sort(function(c1, c2) {
      return c1.length - c2.length;
    });

    return combinations;
  }

  function createNodeBackground(colors) {
    if (colors.length == 1) {
      return {
        'background-color': toRGB(colors[0])
      };
    }

    var css = {};

    for (var i = 0; i < colors.length; i++) {
      css['pie-' + (i + 1) + '-background-color'] = toRGB(colors[i]);
      css['pie-' + (i + 1) + '-background-size'] = 100 / colors.length;
    }

    return css;
  }

  function createEdgeColor(color) {
    return {
      'line-color': toRGB(color)
    };
  }

  function mix(color1, color2) {
    var r = Math.round((color1[0] + color2[0]) / 2);
    var g = Math.round((color1[1] + color2[1]) / 2);
    var b = Math.round((color1[2] + color2[2]) / 2);

    return [r, g, b];
  }

  function toRGB(color) {
    return 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
  }

  var contextMenu = {
    selector: 'core',
    commands: [{
      content: 'Apply Layout',
      select: function() {
        $mdDialog.show({
          controller: function($scope) {
            $scope.select = function(layout) {
              $mdDialog.hide(layout);
            };
          },
          template: `
            <md-dialog aria-label="Apply Layout">
              <md-toolbar><dialog-toolbar title="Apply Layout"></dialog-toolbar></md-toolbar>
              <md-dialog-content><layout-select on-select="select(layout)"></layout-select></md-dialog-content>
            </md-dialog>
          `,
          parent: angular.element(document.body),
          clickOutsideToClose: true
        }).then(function(layout) {
          _cy.layout(layout);
        });
      }
    }, {
      content: 'Zoom to Graph',
      select: function() {
        _cy.fit();
      }
    }, {
      content: 'Clear Trace',
      select: function() {
        tracingService.clearTrace();
        repaint();
      }
    }]
  };

  var stationContextMenu = {
    selector: 'node',
    commands: [{
      content: 'Show Forward Trace',
      select: function(station) {
        tracingService.clearTrace();
        tracingService.showStationForwardTrace(station.id());
        repaint();
      }
    }, {
      content: 'Show Backward Trace',
      select: function(station) {
        tracingService.clearTrace();
        tracingService.showStationBackwardTrace(station.id());
        repaint();
      }
    }, {
      content: 'Show Whole Trace',
      select: function(station) {
        tracingService.clearTrace();
        tracingService.showStationForwardTrace(station.id());
        tracingService.showStationBackwardTrace(station.id());
        repaint();
      }
    }, {
      content: 'Mark/Unmark as Outbreak',
      select: function(station) {
        tracingService.toggleOutbreakStation(station.id());
        graph.setNodeSize(_nodeSize);
        repaint();
      }
    }]
  };

  var deliveryContextMenu = {
    selector: 'edge',
    commands: [{
      content: 'Show Forward Trace',
      select: function(delivery) {
        tracingService.clearTrace();
        tracingService.showDeliveryForwardTrace(delivery.id());
        repaint();
      }
    }, {
      content: 'Show Backward Trace',
      select: function(delivery) {
        tracingService.clearTrace();
        tracingService.showDeliveryBackwardTrace(delivery.id());
        repaint();
      }
    }, {
      content: 'Show Whole Trace',
      select: function(delivery) {
        tracingService.clearTrace();
        tracingService.showDeliveryForwardTrace(delivery.id());
        tracingService.showDeliveryBackwardTrace(delivery.id());
        repaint();
      }
    }]
  };
});
<|endoftext|>


<commit_before>var FormValidation = function () {

    // validation using icons
    var handleValidation = function() {

        // for more info visit the official plugin documentation:
        // http://docs.jquery.com/Plugins/Validation

        var form2 = $('#form_sample_2');
        var error2 = $('.alert-danger', form2);
        var success2 = $('.alert-success', form2);

        form2.validate({
            errorElement: 'span', //default input error message container
            errorClass: 'help-block help-block-error', // default input error message class
            focusInvalid: false, // do not focus the last invalid input
            ignore: "",  // validate all fields including form hidden input
            rules: {
                unit_name: {
                    required: true
                },
                "unit_category[]": {
                    required: true
                },
                credibility: {
                    required: true
                },
                country: {
                    required: true
                },
                state: {
                    required: function(){
                        var c_id = $("#country").val();
                        if(c_id  == "global")
                            return false;
                        else
                            return true;
                    }
                },
                city: {
                    required: function(){
                        var c_id = $("#country").val();
                        if(c_id  == "global")
                            return false;
                        else
                            return true;
                    }
                }
            },

            invalidHandler: function (event, validator) { //display error alert on form submit
                success2.hide();
                error2.show();
                App.scrollTo(error2, -200);
            },

            errorPlacement: function (error, element) { // render error placement for each input type
                var field_name = $(element).attr('name');
                if(field_name == "unit_category[]" || field_name == "country" || field_name == "state" || field_name == "city")
                    $(element).parents('.input-icon').find(".select2").find(".select2-selection").css("border-color","#a94442");

                if(field_name == "unit_category[]"){
                    var icon = $(element).parents('.input-icon').children('i');
                }
                else
                    var icon = $(element).parent('.input-icon').children('i');
                icon.removeClass('fa-check').addClass("fa-warning");
                icon.attr("data-original-title", error.text()).tooltip({'container': 'body'});
            },

            highlight: function (element) { // hightlight error inputs
                $(element)
                    .closest('.col-sm-4').removeClass("has-success").addClass('has-error'); // set error class to the control group

            },

            unhighlight: function (element) { // revert the change done by hightlight

            },

            success: function (label, element) {
                var field_name = $(element).attr('name');
                if(field_name == "unit_category[]")
                    var icon = $(element).parents('.input-icon').children('i');
                else
                    var icon = $(element).parent('.input-icon').children('i');
                $(element).closest('.col-sm-4').removeClass('has-error').addClass('has-success'); // set success class to the control group
                icon.removeClass("fa-warning").addClass("fa-check");

                if(field_name == "unit_category[]" || field_name == "country" || field_name == "state" || field_name == "city")
                    $(element).parents('.input-icon').find(".select2").find(".select2-selection").css("border-color","#3c763d");

            },

            submitHandler: function (form) {
                success2.show();
                error2.hide();
                form.submit(); // submit the form

            }
        });
    }

    return {
        //main function to initiate the module
        init: function () {
            handleValidation();
        }
    };

}();

$(document).ready(function() {
    FormValidation.init();

    $('.summernote').ckeditor();

    function formatSkills (repo) {
        if (repo.loading) return repo.text;

        var markup = "
" +
            "
" +
            "
" + repo.name + "

";
        return markup;
    }

    function formatSkillsSelection (repo) {
        return repo.text;
    }
    var categoriesSelect2 = $("#unit_category").select2({
        allowClear: true,
        width: '100%',
        displayValue:'skill_name',
        placeholder:'Select Category',
        ajax: {
            url: siteURL+"/unit_category/get_categories",
            dataType: 'json',
            delay: 250,
            data: function (params) {
                return {
                    term: params.term, // search term
                    page: params.page
                };
            },
            processResults: function (data, params) {

                // parse the results into the format expected by Select2
                // since we are using custom formatting functions we do not need to
                // alter the remote JSON data, except to indicate that infinite
                // scrolling can be used
                params.page = params.page || 1;

                return {
                    results: data.items,
                    pagination: {
                        //more: (params.page * 1) < data.total_counts
                        more:false
                    }
                };
            },
            cache: true
        },
        escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
        minimumInputLength: 1,
        templateResult: formatSkills, // omitted for brevity, see the source of this page
        templateSelection: formatSkillsSelection // omitted for brevity, see the source of this page
    });

    categoriesSelect2.on("select2:unselect",function(e){
        var id = e.params.data.id;
        var index = selected_categories_id.indexOf(id);
        if (index > -1) {
            selected_categories_id.splice(index, 1);
        }
        return false;
    });

    $("#related_to").select2({
        theme: "bootstrap",
        allowClear: true,
        placeholder: "Select an option"
    });

    $(".browse-categories").on('click',function(){
        $.ajax({
            type:'get',
            url:siteURL+'/unit_category/browse_categories',
            dataType:'json',
            success:function(resp){
                if(resp.success){
                    $(".div-table-second-cell").css('z-index','100');
                    $(".list-item-main").css('z-index','100');
                    browse_category_box = bootbox.dialog({
                        message: resp.html,
                        title: "Browse Category",
                        buttons: {
                            success: {
                                label: "Set Category",
                                className: "btn-success okay-btn",
                                callback: function(e) {

                                    if($(".hierarchy_parent").length == 1){
                                        selected_categories_id.push($("#category_firstbox").val());
                                    }
                                    if($.trim(selected_categories_id) != ""){
                                        $("#unit_category").select2('val',selected_categories_id);
                                    }
                                    else {
                                        toastr['error']('Please select category', '');
                                        return false;
                                    }
                                }
                            }
                        }
                    });
                    browse_category_box.on("shown.bs.modal", function (e) {
                        browse_category_box.find('.okay-btn').prop('disabled',true);
                    });
                    browse_category_box.on("hidden.bs.modal", function (e) {
                        $(".list-item-main").css('z-index','99999');
                        $(".div-table-second-cell").css('z-index','99999');
                        browse_category_box='';
                    });

                    browse_category_box.modal('show');
                }
            }
        });
        return false;
    });

});

<commit_msg>Fixed CKEditor for saving data.<commit_after>var FormValidation = function () {

    // validation using icons
    var handleValidation = function() {

        // for more info visit the official plugin documentation:
        // http://docs.jquery.com/Plugins/Validation

        var form2 = $('#form_sample_2');
        var error2 = $('.alert-danger', form2);
        var success2 = $('.alert-success', form2);

        form2.validate({
            errorElement: 'span', //default input error message container
            errorClass: 'help-block help-block-error', // default input error message class
            focusInvalid: false, // do not focus the last invalid input
            ignore: "",  // validate all fields including form hidden input
            rules: {
                unit_name: {
                    required: true
                },
                "unit_category[]": {
                    required: true
                },
                credibility: {
                    required: true
                },
                country: {
                    required: true
                },
                state: {
                    required: function(){
                        var c_id = $("#country").val();
                        if(c_id  == "global")
                            return false;
                        else
                            return true;
                    }
                },
                city: {
                    required: function(){
                        var c_id = $("#country").val();
                        if(c_id  == "global")
                            return false;
                        else
                            return true;
                    }
                }
            },

            invalidHandler: function (event, validator) { //display error alert on form submit
                success2.hide();
                error2.show();
                App.scrollTo(error2, -200);
            },

            errorPlacement: function (error, element) { // render error placement for each input type
                var field_name = $(element).attr('name');
                if(field_name == "unit_category[]" || field_name == "country" || field_name == "state" || field_name == "city")
                    $(element).parents('.input-icon').find(".select2").find(".select2-selection").css("border-color","#a94442");

                if(field_name == "unit_category[]"){
                    var icon = $(element).parents('.input-icon').children('i');
                }
                else
                    var icon = $(element).parent('.input-icon').children('i');
                icon.removeClass('fa-check').addClass("fa-warning");
                icon.attr("data-original-title", error.text()).tooltip({'container': 'body'});
            },

            highlight: function (element) { // hightlight error inputs
                $(element)
                    .closest('.col-sm-4').removeClass("has-success").addClass('has-error'); // set error class to the control group

            },

            unhighlight: function (element) { // revert the change done by hightlight

            },

            success: function (label, element) {
                var field_name = $(element).attr('name');
                if(field_name == "unit_category[]")
                    var icon = $(element).parents('.input-icon').children('i');
                else
                    var icon = $(element).parent('.input-icon').children('i');
                $(element).closest('.col-sm-4').removeClass('has-error').addClass('has-success'); // set success class to the control group
                icon.removeClass("fa-warning").addClass("fa-check");

                if(field_name == "unit_category[]" || field_name == "country" || field_name == "state" || field_name == "city")
                    $(element).parents('.input-icon').find(".select2").find(".select2-selection").css("border-color","#3c763d");

            },

            submitHandler: function (form) {
                success2.show();
                error2.hide();
                form.submit(); // submit the form

            }
        });
    }

    return {
        //main function to initiate the module
        init: function () {
            handleValidation();
        }
    };

}();

$(document).ready(function() {
    FormValidation.init();

    $('.summernote').ckeditor();

    CKEDITOR.on('instanceReady', function(){
        $.each( CKEDITOR.instances, function(instance) {
            CKEDITOR.instances[instance].on("change", function(e) {
                for ( instance in CKEDITOR.instances )
                    CKEDITOR.instances[instance].updateElement();
            });
        });
    });

    function formatSkills (repo) {
        if (repo.loading) return repo.text;

        var markup = "
" +
            "
" +
            "
" + repo.name + "

";
        return markup;
    }

    function formatSkillsSelection (repo) {
        return repo.text;
    }
    var categoriesSelect2 = $("#unit_category").select2({
        allowClear: true,
        width: '100%',
        displayValue:'skill_name',
        placeholder:'Select Category',
        ajax: {
            url: siteURL+"/unit_category/get_categories",
            dataType: 'json',
            delay: 250,
            data: function (params) {
                return {
                    term: params.term, // search term
                    page: params.page
                };
            },
            processResults: function (data, params) {

                // parse the results into the format expected by Select2
                // since we are using custom formatting functions we do not need to
                // alter the remote JSON data, except to indicate that infinite
                // scrolling can be used
                params.page = params.page || 1;

                return {
                    results: data.items,
                    pagination: {
                        //more: (params.page * 1) < data.total_counts
                        more:false
                    }
                };
            },
            cache: true
        },
        escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
        minimumInputLength: 1,
        templateResult: formatSkills, // omitted for brevity, see the source of this page
        templateSelection: formatSkillsSelection // omitted for brevity, see the source of this page
    });

    categoriesSelect2.on("select2:unselect",function(e){
        var id = e.params.data.id;
        var index = selected_categories_id.indexOf(id);
        if (index > -1) {
            selected_categories_id.splice(index, 1);
        }
        return false;
    });

    $("#related_to").select2({
        theme: "bootstrap",
        allowClear: true,
        placeholder: "Select an option"
    });

    $(".browse-categories").on('click',function(){
        $.ajax({
            type:'get',
            url:siteURL+'/unit_category/browse_categories',
            dataType:'json',
            success:function(resp){
                if(resp.success){
                    $(".div-table-second-cell").css('z-index','100');
                    $(".list-item-main").css('z-index','100');
                    browse_category_box = bootbox.dialog({
                        message: resp.html,
                        title: "Browse Category",
                        buttons: {
                            success: {
                                label: "Set Category",
                                className: "btn-success okay-btn",
                                callback: function(e) {

                                    if($(".hierarchy_parent").length == 1){
                                        selected_categories_id.push($("#category_firstbox").val());
                                    }
                                    if($.trim(selected_categories_id) != ""){
                                        $("#unit_category").select2('val',selected_categories_id);
                                    }
                                    else {
                                        toastr['error']('Please select category', '');
                                        return false;
                                    }
                                }
                            }
                        }
                    });
                    browse_category_box.on("shown.bs.modal", function (e) {
                        browse_category_box.find('.okay-btn').prop('disabled',true);
                    });
                    browse_category_box.on("hidden.bs.modal", function (e) {
                        $(".list-item-main").css('z-index','99999');
                        $(".div-table-second-cell").css('z-index','99999');
                        browse_category_box='';
                    });

                    browse_category_box.modal('show');
                }
            }
        });
        return false;
    });

});

<|endoftext|>


<commit_before>
'use strict';

/* Action type constants. */
export const RUN_TEST = 'RUN_TEST';
export const CODE_CHANGED = 'CODE_CHANGED';
export const OUTPUT_CHANGED = 'OUTPUT_CHANGED';
export const TESTS_STARTED = 'TESTS_STARTED';
export const TESTS_FINISHED = 'TESTS_FINISHED';
export const START_CHALLENGE = 'START_CHALLENGE';
export const NEXT_CHALLENGE = 'NEXT_CHALLENGE';

export const TIMER_FINISHED = 'TIMER_FINISHED';
export const TIMER_UPDATED = 'TIMER_UPDATED';
export const TIMER_STARTED = 'TIMER_STARTED';
export const STOP_TIMER = 'STOP_TIMER';
export const FINISH_SESSION = 'FINISH_SESSION';

/* Thunk action which runs the test cases against user code. */
export function runTests(userCode, currChallenge) {
  return dispatch => {
    dispatch(actionTestsStarted());

    // Eval user code inside worker
    // http://stackoverflow.com/questions/9020116/is-it-possible-to-restrict-the-scope-of-a-javascript-function/36255766#36255766
    function createWorker () {
      return new Promise((resolve, reject) => {
        const wk = new Worker('../../public/js/worker.bundle.js');
        wk.postMessage([userCode, currChallenge]);
        wk.onmessage = e => {
          console.log(`worker onmessage result: ${e.data}`);
          resolve(e.data);
        };
      });
    }

    createWorker()
      .then(workerData => {
        dispatch(onOutputChange(workerData[0].output));
        if (workerData.length > 1) {
          dispatch(actionTestsFinished(workerData.slice(1)));
        }
      });
  };
}

let timer = null;

/* Thunk action to start the timer. */
export function startTimer() {
  return dispatch => {
    clearInterval(timer);
    dispatch(actionTimerStarted());
    timer = setInterval(() => {
      dispatch(actionTimerUpdated());
    }, 1000 / 60);
  };
}

export function stopTimer() {
  clearInterval(timer);
  return {
    type: STOP_TIMER
  };
}

/* Dispatched when a user starts running the tests.*/
export function actionTestsStarted() {
  return {
    type: TESTS_STARTED
  };
}

/* Dispatched when the tests finish. */
export function actionTestsFinished(testResults) {
  return {
    type: TESTS_FINISHED,
    testResults
  };
}

export function startChallenge() {
  return {
    type: START_CHALLENGE
  };
}

export function nextChallenge() {
  return {
    type: NEXT_CHALLENGE
  };
}

export function onCodeChange(newCode) {
  return {
    type: CODE_CHANGED,
    code: newCode
  };
}

export function actionTimerStarted() {
  return {
    type: TIMER_STARTED
  };
}

export function actionTimerFinished() {
  return {
    type: TIMER_FINISHED
  };
}

export function actionTimerUpdated() {
  return {
    type: TIMER_UPDATED
  };
}

export function onOutputChange(newOutput) {
  return {
    type: OUTPUT_CHANGED,
    userOutput: newOutput
  };
}

export function actionFinishSession() {
  return {
    type: FINISH_SESSION
  };
}
<commit_msg>Added timer max value changed.<commit_after>
'use strict';

/* Action type constants. */
export const RUN_TEST = 'RUN_TEST';
export const CODE_CHANGED = 'CODE_CHANGED';
export const OUTPUT_CHANGED = 'OUTPUT_CHANGED';
export const TESTS_STARTED = 'TESTS_STARTED';
export const TESTS_FINISHED = 'TESTS_FINISHED';
export const START_CHALLENGE = 'START_CHALLENGE';
export const NEXT_CHALLENGE = 'NEXT_CHALLENGE';

export const TIMER_FINISHED = 'TIMER_FINISHED';
export const TIMER_UPDATED = 'TIMER_UPDATED';
export const TIMER_STARTED = 'TIMER_STARTED';
export const STOP_TIMER = 'STOP_TIMER';
export const FINISH_SESSION = 'FINISH_SESSION';

export const TIMER_MAX_VALUE_CHANGED = 'TIMER_MAX_VALUE_CHANGED';

/* Thunk action which runs the test cases against user code. */
export function runTests(userCode, currChallenge) {
  return dispatch => {
    dispatch(actionTestsStarted());

    // Eval user code inside worker
    // http://stackoverflow.com/questions/9020116/is-it-possible-to-restrict-the-scope-of-a-javascript-function/36255766#36255766
    function createWorker () {
      return new Promise((resolve, reject) => {
        const wk = new Worker('../../public/js/worker.bundle.js');
        wk.postMessage([userCode, currChallenge]);
        wk.onmessage = e => {
          console.log(`worker onmessage result: ${e.data}`);
          resolve(e.data);
        };
      });
    }

    createWorker()
      .then(workerData => {
        dispatch(onOutputChange(workerData[0].output));
        if (workerData.length > 1) {
          dispatch(actionTestsFinished(workerData.slice(1)));
        }
      });
  };
}

let timer = null;

/* Thunk action to start the timer. */
export function startTimer() {
  return dispatch => {
    clearInterval(timer);
    dispatch(actionTimerStarted());
    timer = setInterval(() => {
      dispatch(actionTimerUpdated());
    }, 1000 / 60);
  };
}

export function stopTimer() {
  clearInterval(timer);
  return {
    type: STOP_TIMER
  };
}

/* Dispatched when a user starts running the tests.*/
export function actionTestsStarted() {
  return {
    type: TESTS_STARTED
  };
}

/* Dispatched when the tests finish. */
export function actionTestsFinished(testResults) {
  return {
    type: TESTS_FINISHED,
    testResults
  };
}

export function startChallenge() {
  return {
    type: START_CHALLENGE
  };
}

export function nextChallenge() {
  return {
    type: NEXT_CHALLENGE
  };
}

export function onCodeChange(newCode) {
  return {
    type: CODE_CHANGED,
    code: newCode
  };
}

export function actionTimerStarted() {
  return {
    type: TIMER_STARTED
  };
}

export function actionTimerFinished() {
  return {
    type: TIMER_FINISHED
  };
}

export function actionTimerUpdated() {
  return {
    type: TIMER_UPDATED
  };
}

export function actionTimerMaxValueChanged(timerMaxValue) {
  return {
    type: TIMER_MAX_VALUE_CHANGED,
    timerMaxValue
  };
}

export function onOutputChange(newOutput) {
  return {
    type: OUTPUT_CHANGED,
    userOutput: newOutput
  };
}

export function actionFinishSession() {
  return {
    type: FINISH_SESSION
  };
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Help Article', {
	refresh: function(frm) {
		frm.dashboard.clear_headline();

		frm.dashboard.set_headline_alert(`

						Helpful ${frm.doc.helpful}

						Not Helpful ${frm.doc.not_helpful}

		`);
	}
});
<commit_msg>fix(Help Article): show 0 instead of undefined when value not set in dashboard<commit_after>// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Help Article', {
	refresh: function(frm) {
		frm.dashboard.clear_headline();

		frm.dashboard.set_headline_alert(`

						Helpful ${frm.doc.helpful || 0}

						Not Helpful ${frm.doc.not_helpful || 0}

		`);
	}
});
<|endoftext|>


<commit_before>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
var app = angular.module('starter', ['ionic', 'ionic-material']);

app.run(function ($ionicPlatform) {
  $ionicPlatform.ready(function () {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)

    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if (window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

app.config(function ($stateProvider, $urlRouterProvider) {
  $stateProvider

    .state('app', {
      url: '/app',
      abstract: true,
      templateUrl: 'templates/menu.html',
      controller: 'AppCtrl'
    })

    .state('app.lists', {
      url: '/lists',
      views: {
        'menuContent': {
          templateUrl: 'templates/lists.html',
          controller: 'ListsCtrl'
        }
      }
    })

    .state('app.ink', {
      url: '/ink',
      views: {
        'menuContent': {
          templateUrl: 'templates/ink.html',
          controller: 'InkCtrl'
        }
      }
    })

    .state('app.motion', {
      url: '/motion',
      views: {
        'menuContent': {
          templateUrl: 'templates/motion.html',
          controller: 'MotionCtrl'
        }
      }
    })

    .state('app.home', {
      url: '/home',
      views: {
        'menuContent': {
          templateUrl: 'templates/home.html',
          controller: 'HomeCtrl'
        }
      }
    })

    .state('app.schedule', {
      url: '/schedule',
      views: {
        'menuContent': {
          templateUrl: 'templates/schedule.html',
          controller: 'ScheduleCtrl'
        }
      }
    })

    .state('app.map', {
      url: '/map',
      views: {
        'menuContent': {
          templateUrl: 'templates/map.html'
        }
      }
    })

    .state('app.extensions', {
      url: '/extensions',
      views: {
        'menuContent': {
          templateUrl: 'templates/extensions.html',
          controller: 'ExtensionsCtrl'
        }
      }
    })

    .state('app.about', {
      url: '/about',
      views: {
        'menuContent': {
          templateUrl: 'templates/about.html'
        }
      }
    })

    .state('app.register', {
      url: '/register',
      views: {
        'menuContent': {
          templateUrl: 'templates/register.html'
        }
      }
    })

    /*.state('app.components', {
      url: '/components',
      views: {
        'menuContent': {
          templateUrl: 'templates/components.html'
        }
      }
    })*/
  ;

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/home');
});
<commit_msg>set schedule as default page<commit_after>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
var app = angular.module('starter', ['ionic', 'ionic-material']);

app.run(function ($ionicPlatform) {
  $ionicPlatform.ready(function () {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)

    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if (window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

app.config(function ($stateProvider, $urlRouterProvider) {
  $stateProvider

    .state('app', {
      url: '/app',
      abstract: true,
      templateUrl: 'templates/menu.html',
      controller: 'AppCtrl'
    })

    .state('app.lists', {
      url: '/lists',
      views: {
        'menuContent': {
          templateUrl: 'templates/lists.html',
          controller: 'ListsCtrl'
        }
      }
    })

    .state('app.ink', {
      url: '/ink',
      views: {
        'menuContent': {
          templateUrl: 'templates/ink.html',
          controller: 'InkCtrl'
        }
      }
    })

    .state('app.motion', {
      url: '/motion',
      views: {
        'menuContent': {
          templateUrl: 'templates/motion.html',
          controller: 'MotionCtrl'
        }
      }
    })

    .state('app.home', {
      url: '/home',
      views: {
        'menuContent': {
          templateUrl: 'templates/home.html',
          controller: 'HomeCtrl'
        }
      }
    })

    .state('app.schedule', {
      url: '/schedule',
      views: {
        'menuContent': {
          templateUrl: 'templates/schedule.html',
          controller: 'ScheduleCtrl'
        }
      }
    })

    .state('app.map', {
      url: '/map',
      views: {
        'menuContent': {
          templateUrl: 'templates/map.html'
        }
      }
    })

    .state('app.extensions', {
      url: '/extensions',
      views: {
        'menuContent': {
          templateUrl: 'templates/extensions.html',
          controller: 'ExtensionsCtrl'
        }
      }
    })

    .state('app.about', {
      url: '/about',
      views: {
        'menuContent': {
          templateUrl: 'templates/about.html'
        }
      }
    })

    .state('app.register', {
      url: '/register',
      views: {
        'menuContent': {
          templateUrl: 'templates/register.html'
        }
      }
    })

    /*.state('app.components', {
      url: '/components',
      views: {
        'menuContent': {
          templateUrl: 'templates/components.html'
        }
      }
    })*/
  ;

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/schedule');
});
<|endoftext|>