<commit_before>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/List.js"/>

Ext.namespace("Mobile.SalesLogix.Calendar");

(function() {
    Mobile.SalesLogix.Calendar.UserActivityList = Ext.extend(Sage.Platform.Mobile.List, {
        currentDate: Date.today(),

        //Templates
        itemTemplate: new Simplate([
            '
',
            '

',
            '{%! $$.contentTemplate %}',
            '
'
        ]),
        activityTimeTemplate: new Simplate([
            '{% if ($.Activity.Timeless) { %}',
            'Timeless',
            '{% } else { %}',
            '{%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "h:mm") %}',
            ' {%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "tt") %},',
            '{% } %}'
        ]),
        contentTemplate: new Simplate([
            '
',
            '{%= $$.activityTimeTemplate.apply($) %}',
            ' {%: $.Activity.Description %}',
            '
',
            '
{%= $$.nameTemplate.apply($) %}
'
        ]),
        nameTemplate: new Simplate([
            '{% if ($.Activity.ContactName) { %}',
            '{%: $.Activity.ContactName %} / {%: $.Activity.AccountName %}',
            '{% } else if ($.Activity.AccountName) { %}',
            '{%: $.Activity.AccountName %}',
            '{% } else { %}',
            '{%: $.Activity.LeadName %}',
            '{% } %}'
        ]),
        viewTemplate: new Simplate([
            '
',
            '{%! $.searchTemplate %}',
            'fix for android issue #6059',
            '
',
            '<button data-tool="today" data-action="getTodayActivities" class="button headerButton active">Today</button>',
            '<button data-tool="day" class="button">Day</button>',
            '<button data-tool="month" data-action="navigateToMonthView" class="button">Month</button>',
            '
',
            '
',
            '

',
            '<button data-tool="next" data-action="getNextActivities" class="button button-next lightGreenButton"></button>',
            '<button data-tool="prev" data-action="getPrevActivities" class="button button-prev lightGreenButton"></button>',
            '
',
            '

',
            '{%! $.moreTemplate %}',
            '
'
        ]),

        //Localization
        titleText: 'Calendar',

        //View Properties
        hideSearch: true,
        id: 'useractivity_list',
        icon: 'content/images/icons/Calendar_24x24.png',
        detailView: 'activity_detail',
        detailViewForLead: 'activity_detail_for_lead',
        insertView: 'activity_types_list',
        queryOrderBy: 'Activity.Timeless desc, Activity.StartDate',
        querySelect: [
            'Activity/Description',
            'Activity/StartDate',
            'Activity/Type',
            'Activity/AccountName',
            'Activity/ContactName',
            'Activity/LeadId',
            'Activity/LeadName',
            'Activity/UserId',
            'Activity/Timeless'
        ],
        resourceKind: 'useractivities',

        init: function() {
            Ext.apply(this.attachmentPoints, {
                dateTextEl: '.date-text',
                splitButton: '.split-buttons',
                todayButton: '.button[data-tool="today"]',
                dayButton: '.button[data-tool="day"]',
                monthButton: '.button[data-tool="month"]'
            });

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.init.apply(this, arguments);
        },
        initEvents: function() {
            Mobile.SalesLogix.Calendar.UserActivityList.superclass.initEvents.apply(this, arguments);

            App.on('refresh', this.refreshOnActivityInsert, this);
        },
        refreshOnActivityInsert: function(o) {
            if (o.resourceKind === 'activities')
            {
                this.refreshRequired = true;
            }
        },
        show: function(options) {
            if (!options) options = {};
            options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.show.call(this, options);
        },
        getNextActivities: function() {
            this.currentDate.add({day: 1});
            this.getActivities();
        },
        getTodayActivities: function() {
            if (this.currentDate.equals(Date.today())) return;

            this.currentDate = Date.today();
            this.getActivities();
        },
        getPrevActivities: function() {
            this.currentDate.add({day: -1});
            this.getActivities();
        },
        getActivities: function(date) {
            this.clear();
            this.setOptions();
            this.setSplitButtonStatus();
            this.requestData();
        },
        getActivitiesForDay: function() {
            var view = App.getActiveView();
            this.currentDate = view.getDateTime();
            ReUI.back();
            this.getActivities();
        },
        setNavBarTitle: function() {
            this.dateTextEl.update(this.currentDate.toString('dddd, MM/dd/yyyy'));
        },
        getUTCDateString: function(date) {
            var pad = function(n) { return n < 10 ? '0' + n : n };

            return String.format('{0}-{1}-{2}T{3}:{4}:{5}',
                date.getUTCFullYear(),
                pad(date.getUTCMonth() + 1 ),
                pad(date.getUTCDate()),
                pad(date.getUTCHours()),
                pad(date.getUTCMinutes()),
                pad(date.getUTCSeconds())
            );
        },
        formatQueryForActivities: function() {
            var qry = 'UserId eq "{0}" and (Activity.StartDate between @{1}@ and @{2}@) '
                      + 'or (Activity.Timeless eq true and Activity.StartDate between @{3}@ and @{4}@)';

            return String.format(
                qry,
                App.context.user.$key,
                this.getUTCDateString(this.currentDate),
                this.getUTCDateString(this.currentDate.clone().add({day: 1})),
                this.currentDate.toString('yyyy-MM-ddT00:00:00'),
                this.currentDate.toString('yyyy-MM-ddT23:59:59')
            );
        },
        setOptions: function() {
            if (!this.options) this.options = {};
            this.options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();
        },
        setSplitButtonStatus: function() {
            [this.todayButton, this.dayButton, this.monthButton].forEach(function(el){
                el.addClass(['headerButton']);
            });

            if (this.currentDate.equals(Date.today()))
            {
                this.dayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
            else
            {
                this.todayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
        },
        isActivityForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        navigateToMonthView: function() {
            var view = App.getView('slx_calendar');

            if (view)
            {
                view.show({
                    tools: {
                        tbar: [{
                            id: 'cancel',
                            side: 'left',
                            fn: ReUI.back,
                            scope: ReUI
                        }]
                    }
                });
            }
        },
        isActivityForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        navigateToDetailView: function(key, descriptor) {
            var entry = this.entries[key],
                activity = entry.Activity;

            if (this.isActivityForLead(activity))
            {
                var view = App.getView(this.detailViewForLead);
                if (view)
                    view.show({
                        descriptor: activity.Description,
                        key: activity.$key
                    });
            }
            else
            {
                Mobile.SalesLogix.Activity.List.superclass.navigateToDetailView.apply(this, [activity.$key, activity.Description]);
            }
        },
    });
})();
<commit_msg>[#10699135] SLX Calendar View Story   - Fixed a bug, that caused activities created at 12:00 AM to be listed in adjacent day views.<commit_after>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/List.js"/>

Ext.namespace("Mobile.SalesLogix.Calendar");

(function() {
    Mobile.SalesLogix.Calendar.UserActivityList = Ext.extend(Sage.Platform.Mobile.List, {
        currentDate: Date.today(),

        //Templates
        itemTemplate: new Simplate([
            '
',
            '

',
            '{%! $$.contentTemplate %}',
            '
'
        ]),
        activityTimeTemplate: new Simplate([
            '{% if ($.Activity.Timeless) { %}',
            'Timeless',
            '{% } else { %}',
            '{%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "h:mm") %}',
            ' {%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "tt") %},',
            '{% } %}'
        ]),
        contentTemplate: new Simplate([
            '
',
            '{%= $$.activityTimeTemplate.apply($) %}',
            ' {%: $.Activity.Description %}',
            '
',
            '
{%= $$.nameTemplate.apply($) %}
'
        ]),
        nameTemplate: new Simplate([
            '{% if ($.Activity.ContactName) { %}',
            '{%: $.Activity.ContactName %} / {%: $.Activity.AccountName %}',
            '{% } else if ($.Activity.AccountName) { %}',
            '{%: $.Activity.AccountName %}',
            '{% } else { %}',
            '{%: $.Activity.LeadName %}',
            '{% } %}'
        ]),
        viewTemplate: new Simplate([
            '
',
            '{%! $.searchTemplate %}',
            'fix for android issue #6059',
            '
',
            '<button data-tool="today" data-action="getTodayActivities" class="button headerButton active">Today</button>',
            '<button data-tool="day" class="button">Day</button>',
            '<button data-tool="month" data-action="navigateToMonthView" class="button">Month</button>',
            '
',
            '
',
            '

',
            '<button data-tool="next" data-action="getNextActivities" class="button button-next lightGreenButton"></button>',
            '<button data-tool="prev" data-action="getPrevActivities" class="button button-prev lightGreenButton"></button>',
            '
',
            '

',
            '{%! $.moreTemplate %}',
            '
'
        ]),

        //Localization
        titleText: 'Calendar',

        //View Properties
        hideSearch: true,
        id: 'useractivity_list',
        icon: 'content/images/icons/Calendar_24x24.png',
        detailView: 'activity_detail',
        detailViewForLead: 'activity_detail_for_lead',
        insertView: 'activity_types_list',
        queryOrderBy: 'Activity.Timeless desc, Activity.StartDate',
        querySelect: [
            'Activity/Description',
            'Activity/StartDate',
            'Activity/Type',
            'Activity/AccountName',
            'Activity/ContactName',
            'Activity/LeadId',
            'Activity/LeadName',
            'Activity/UserId',
            'Activity/Timeless'
        ],
        resourceKind: 'useractivities',

        init: function() {
            Ext.apply(this.attachmentPoints, {
                dateTextEl: '.date-text',
                splitButton: '.split-buttons',
                todayButton: '.button[data-tool="today"]',
                dayButton: '.button[data-tool="day"]',
                monthButton: '.button[data-tool="month"]'
            });

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.init.apply(this, arguments);
        },
        initEvents: function() {
            Mobile.SalesLogix.Calendar.UserActivityList.superclass.initEvents.apply(this, arguments);

            App.on('refresh', this.refreshOnActivityInsert, this);
        },
        refreshOnActivityInsert: function(o) {
            if (o.resourceKind === 'activities')
            {
                this.refreshRequired = true;
            }
        },
        show: function(options) {
            if (!options) options = {};
            options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.show.call(this, options);
        },
        getNextActivities: function() {
            this.currentDate.add({day: 1});
            this.getActivities();
        },
        getTodayActivities: function() {
            if (this.currentDate.equals(Date.today())) return;

            this.currentDate = Date.today();
            this.getActivities();
        },
        getPrevActivities: function() {
            this.currentDate.add({day: -1});
            this.getActivities();
        },
        getActivities: function(date) {
            this.clear();
            this.setOptions();
            this.setSplitButtonStatus();
            this.requestData();
        },
        getActivitiesForDay: function() {
            var view = App.getActiveView();
            this.currentDate = view.getDateTime();
            ReUI.back();
            this.getActivities();
        },
        setNavBarTitle: function() {
            this.dateTextEl.update(this.currentDate.toString('dddd, MM/dd/yyyy'));
        },
        getUTCDateString: function(date) {
            var pad = function(n) { return n < 10 ? '0' + n : n };

            return String.format('{0}-{1}-{2}T{3}:{4}:{5}',
                date.getUTCFullYear(),
                pad(date.getUTCMonth() + 1 ),
                pad(date.getUTCDate()),
                pad(date.getUTCHours()),
                pad(date.getUTCMinutes()),
                pad(date.getUTCSeconds())
            );
        },
        formatQueryForActivities: function() {
            var qry = 'UserId eq "{0}" and (Activity.StartDate between @{1}@ and @{2}@) '
                      + 'or (Activity.Timeless eq true and Activity.StartDate between @{3}@ and @{4}@)';

            return String.format(
                qry,
                App.context.user.$key,
                this.getUTCDateString(this.currentDate),
                this.getUTCDateString(this.currentDate.clone().add({day: 1, second: -1})),
                this.currentDate.toString('yyyy-MM-ddT00:00:00'),
                this.currentDate.toString('yyyy-MM-ddT23:59:59')
            );
        },
        setOptions: function() {
            if (!this.options) this.options = {};
            this.options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();
        },
        setSplitButtonStatus: function() {
            [this.todayButton, this.dayButton, this.monthButton].forEach(function(el){
                el.addClass(['headerButton']);
            });

            if (this.currentDate.equals(Date.today()))
            {
                this.dayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
            else
            {
                this.todayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
        },
        isActivityForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        navigateToMonthView: function() {
            var view = App.getView('slx_calendar');

            if (view)
            {
                view.show({
                    tools: {
                        tbar: [{
                            id: 'cancel',
                            side: 'left',
                            fn: ReUI.back,
                            scope: ReUI
                        }]
                    }
                });
            }
        },
        isActivityForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        navigateToDetailView: function(key, descriptor) {
            var entry = this.entries[key],
                activity = entry.Activity;

            if (this.isActivityForLead(activity))
            {
                var view = App.getView(this.detailViewForLead);
                if (view)
                    view.show({
                        descriptor: activity.Description,
                        key: activity.$key
                    });
            }
            else
            {
                Mobile.SalesLogix.Activity.List.superclass.navigateToDetailView.apply(this, [activity.$key, activity.Description]);
            }
        },
    });
})();
<|endoftext|>


<commit_before><commit_msg>Added set UUID cookie example to FirebaseExamples.js<commit_after><|endoftext|>


<commit_before>'use strict';

/*
var cl = console.log;
console.log = function(){
  console.trace();
  cl.apply(console,arguments);
};
*/

// Requires meanio .
var mean = require('meanio');
var cluster = require('cluster');

// Code to run if we're in the master process or if we are not in debug mode/ running tests

if ((cluster.isMaster) &&
  (process.execArgv.indexOf('--debug') < 0) &&
  (process.env.NODE_ENV!=='test') && (process.env.NODE_ENV!=='development') &&
  (process.execArgv.indexOf('--singleProcess')<0)) {
//if (cluster.isMaster) {

    console.log('for real!');
    // Count the machine's CPUs
    //var cpuCount = require('os').cpus().length;
    var cpuCount = 1;

    // Create a worker for each CPU
    for (var i = 0; i < cpuCount; i += 1) {
        console.log ('forking ',i);
        cluster.fork();
    }

    // Listen for dying workers
    cluster.on('exit', function (worker) {
        // Replace the dead worker, we're not sentimental
        console.log('Worker ' + worker.id + ' died :(');
        cluster.fork();

    });

// Code to run if we're in a worker process
} else {

    var workerId = 0;
    if (!cluster.isMaster)
    {
        workerId = cluster.worker.id;
    }
// Creates and serves mean application
    mean.serve({ workerid: workerId /* more options placeholder*/ }, function (app) {
      var config = app.config.clean;
        var port = config.https && config.https.port ? config.https.port : config.http.port;
        console.log('Mean app started on port ' + port + ' (' + process.env.NODE_ENV + ') cluster.worker.id:', workerId);
    });
}
<commit_msg>Cpu process test<commit_after>'use strict';

/*
var cl = console.log;
console.log = function(){
  console.trace();
  cl.apply(console,arguments);
};
*/

// Requires meanio .
var mean = require('meanio');
var cluster = require('cluster');

// Code to run if we're in the master process or if we are not in debug mode/ running tests

if ((cluster.isMaster) &&
  (process.execArgv.indexOf('--debug') < 0) &&
  (process.env.NODE_ENV!=='test') && (process.env.NODE_ENV!=='development') &&
  (process.execArgv.indexOf('--singleProcess')<0)) {
//if (cluster.isMaster) {

    console.log('for real!');
    // Count the machine's CPUs
    var cpuCount = require('os').cpus().length;
    //var cpuCount = 1;

    // Create a worker for each CPU
    for (var i = 0; i < cpuCount; i += 1) {
        console.log ('forking ',i);
        cluster.fork();
    }

    // Listen for dying workers
    cluster.on('exit', function (worker) {
        // Replace the dead worker, we're not sentimental
        console.log('Worker ' + worker.id + ' died :(');
        cluster.fork();

    });

// Code to run if we're in a worker process
} else {

    var workerId = 0;
    if (!cluster.isMaster)
    {
        workerId = cluster.worker.id;
    }
// Creates and serves mean application
    mean.serve({ workerid: workerId /* more options placeholder*/ }, function (app) {
      var config = app.config.clean;
        var port = config.https && config.https.port ? config.https.port : config.http.port;
        console.log('Mean app started on port ' + port + ' (' + process.env.NODE_ENV + ') cluster.worker.id:', workerId);
    });
}
<|endoftext|>


<commit_before>(function () {
    'use strict';
    // Dependencies
    const restify = require('restify');
    const socketio = require('socket.io');
    const redis = require('redis');
    const Promise = require('bluebird');
    const socketIORedis = require('socket.io-redis');

    // Setup Redis client with promises
    Promise.promisifyAll(redis.RedisClient.prototype);
    Promise.promisifyAll(redis.Multi.prototype);

    // Configuration
    const port = 8080;
    const burst = 100;
    const throttleRate = 50;

    var server = restify.createServer();
    var io = socketio.listen(server);
    var redisClient = redis.createClient({
        host: process.env.REDIS_HOST,
        port: process.env.REDIS_PORT
    });
    io.adapter(socketIORedis({host: process.env.REDIS_HOST, port: process.env.REDIS_PORT}));

    server.use(restify.CORS());
    server.use(restify.gzipResponse());
    server.use(restify.bodyParser());
    server.use(restify.throttle({
        burst: burst,
        rate: throttleRate,
        ip: true
    }));
    server.use(restify.conditionalRequest());

    // Health Check
    server.get('/', function (req, res) {
        res.status(200);
        res.send({
            message: 'Oh hai there!'
        });
    });

    var roomNamespaces = {};
    var defaultInstruments = {
        drums: false,
        bass: false,
        lead: false,
        rhythm: false
    };

    server.get('/flush', function (req, res) {
        console.log('Flushing Current State');
        redisClient
            .flushallAsync()
            .then(function () {
                res.status(204);
                res.end();
            });
    });

    server.get('/rooms', function (req, res, next) {
        console.log('Retrieving Room List');
        redisClient
            .getAsync('rooms')
            .then(JSON.parse)
            .then(function (rooms) {
                console.log('Got Room List');
                res.send(rooms || []);
            })
            .catch(next);
    });
    server.post('/rooms/:room', function (req, res, next) {
        let roomName = req.params.room;
        console.log('Creating Room ' + roomName);
        redisClient
            .getAsync('rooms')
            .then(JSON.parse)
            .then(function (rooms) {
                rooms = rooms || [];

                if (rooms.indexOf(roomName) >= 0) {
                    console.log('Room ' + roomName + ' already exists');
                    res.status(419);
                    return res.send({
                        name: 'RoomAlreadyExists',
                        message: 'The room ' + roomName + ' already exists',
                        statusCode: 419
                    });
                }

                rooms.push(roomName);

                console.log('Storing newly created room');
                return Promise.all([
                    redisClient.setAsync('rooms:' + roomName, JSON.stringify(defaultInstruments)),
                    redisClient.setAsync('rooms', JSON.stringify(rooms))
                ]).then(function () {
                    console.log('Room stored, setting it up');
                    setupRoom(roomName);
                    res.status(204);
                    res.end();
                });
            })
            .catch(next);
    });
    server.del('/rooms/:room', function (req, res) {
        let roomName = req.params.room;
        console.log('Removing Room ' + roomName);
        redisClient
            .getAsync('rooms')
            .then(JSON.parse)
            .then(function (rooms) {
                rooms = rooms || [];
                let roomIndex = rooms.indexOf(roomName);
                if (roomIndex >= 0) {
                    console.log('Room ' + roomName + ' exists, removing it');
                    rooms.splice(roomIndex, 1);
                    return Promise.all([
                        redisClient.delAsync('rooms:' + roomName),
                        redisClient.setAsync('rooms', JSON.stringify(rooms))
                    ]).then(function () {
                        teardownRoom(roomName);
                        console.log('Deleted room ' + roomName);
                        res.status(204);
                        res.end();
                    });
                }
                teardownRoom(roomName);
                res.status(404);
                res.send({
                    name: 'RoomNotFound',
                    message: 'The room ' + roomName + ' was not found',
                    statusCode: 404
                });
            });
    });

    server.get('/rooms/:room/instruments', function (req, res) {
        let roomName = req.params.room;
        console.log('Retrieving instruments for ' + roomName);
        redisClient
            .getAsync('rooms:' + roomName)
            .then(JSON.parse)
            .then(function (room) {
                if (!room) {
                    console.log('Room ' + roomName + 'doesn\'t exist');
                    res.status(404);
                    return res.send({
                        name: 'RoomNotFound',
                        message: 'The room ' + roomName + ' was not found',
                        statusCode: 404
                    });
                }

                console.log('Sending back instruments for room ' + roomName);
                res.send(room);
            });
    });

    server.post('/rooms/:room/instruments/:instrument', function (req, res) {
        let roomName = req.params.room;
        var instrumentName = req.params.instrument;
        console.log('Reserving ' + instrumentName + ' in ' + roomName);
        redisClient
            .getAsync('rooms:' + roomName)
            .then(JSON.parse)
            .then(function (room) {
                if (!room) {
                    console.log('Can\'t reserve ' + instrumentName + ' in ' + roomName + ' room doesn\'t exist');
                    res.status(404);
                    return res.send({
                        name: 'RoomNotFound',
                        message: 'The room ' + roomName + ' was not found',
                        statusCode: 404
                    });
                }

                if (!(instrumentName in room)) {
                    console.log('Can\'t reserve ' + instrumentName + ' in ' + roomName + ' instrument doesn\'t exist');
                    res.status(404);
                    return res.send({
                        name: 'InstrumentNotFound',
                        message: 'The instrument ' + instrumentName + ' was not found',
                        statusCode: 404
                    });
                } else if (room[instrumentName]) {
                    console.log('Can\'t reserve ' + instrumentName + ' in ' + roomName + ' instrument not available');
                    res.status(412);
                    return res.send({
                        name: 'InstrumentNotAvailable',
                        message: 'The instrument ' + instrumentName + ' has already been reserved',
                        statusCode: 412
                    });
                }

                room[instrumentName] = true;
                return redisClient
                    .setAsync('rooms:' + roomName, JSON.stringify(room))
                    .then(function () {
                        console.log('Instrument ' + instrumentName + ' in ' + roomName + ' reserved');
                        io.of('/' + roomName).emit('instrument reserved', instrumentName);
                        io.of('/' + roomName).emit('instruments changed', room);
                        res.status(204);
                        res.end();
                    });
            });
    });

    server.del('/rooms/:room/instruments/:instrument', function (req, res, next) {
        let roomName = req.params.room;
        var instrumentName = req.params.instrument;
        console.log('Releasing ' + instrumentName + ' in ' + roomName);
        releaseInstrument(roomName, instrumentName)
            .then(function () {
                console.log('Released ' + instrumentName + ' in ' + roomName + ' reserved');
                res.status(204);
                res.end();
            })
            .catch(function (reason) {
                console.log('Failed to release ' + instrumentName + ' in ' + roomName + ' because ' + reason);
                console.error(reason);
                res.status(reason.statusCode);
                return res.send(reason);
            });
    });

    server.listen(port, function () {
        console.log('socket.io server listening at %s', server.url);
    });

    function releaseInstrument(roomName, instrumentName) {
        console.log('Releasing Instrument ' + instrumentName + ' in ' + roomName);
        return redisClient
            .getAsync('rooms:' + roomName)
            .then(JSON.parse)
            .then(function (room) {
                if (!room) {
                    console.log('Failed Release ' + instrumentName + ' in ' + roomName + ' because room is not found');
                    return Promise.reject({
                        name: 'RoomNotFound',
                        message: 'The room ' + roomName + ' was not found',
                        statusCode: 404
                    });
                }

                if (!(instrumentName in room)) {
                    console.log('Failed Release ' + instrumentName + ' in ' + roomName + ' because instrument is not found');
                    return Promise.reject({
                        name: 'InstrumentNotFound',
                        message: 'The instrument ' + instrumentName + ' was not found',
                        statusCode: 404
                    });
                } else if (!room[instrumentName]) {
                    console.log('Failed Release ' + instrumentName + ' in ' + roomName + ' because instrument is not reserved');
                    return Promise.reject({
                        name: 'InstrumentNotReserved',
                        message: 'The instrument ' + instrumentName + ' has not yet been reserved',
                        statusCode: 412
                    });
                }

                room[instrumentName] = false;
                return redisClient
                    .setAsync('rooms:' + roomName, JSON.stringify(room))
                    .then(function () {

                        io.of('/' + roomName).emit('instrument released', instrumentName);
                        io.of('/' + roomName).emit('instruments changed', room);
                    })
                    .return(room);
            });
    }

    function setupRoom(roomName) {
        console.log('Setting up room ' + roomName);
        let socketInstruments = {};
        let nsp = io.of('/' + roomName);
        nsp.on('connection', function (socket) {
            console.log('Socket ' + socket.id + ' connected');

            socket.on('reserved instrument', function (instrument) {
                console.log('Instrument ' + instrument + ' has been confirmed reserved in ' + roomName);
                socketInstruments[socket.id] = instrument;
            });

            socket.on('disconnect', function () {
                console.log('Socket ' + socket.id + ' disconnected');
                // If the socket that disconnected has an instrument, release it
                if (socketInstruments[socket.id]) {
                    console.log('Releasing ' + socketInstruments[socket.id] + ' due to disconnect in ' + roomName);
                    releaseInstrument(roomName, socketInstruments[socket.id]);
                    delete socketInstruments[socket.id];
                }
            });

            Object.keys(defaultInstruments).forEach(function (instrument) {
                console.log('Setting up ' + instrument + ' for ' + roomName);
                socket.on('play ' + instrument, function (sound) {
                    console.log('Playing ' + sound + ' for ' + instrument + ' in ' + roomName);
                    io.of('/' + roomName).emit(instrument + ' played', sound);
                });
                socket.on('stop ' + instrument, function (sound) {
                    console.log('Stopping ' + sound + ' for ' + instrument + ' in ' + roomName);
                    io.of('/' + roomName).emit(instrument + ' stopped', sound);
                });
            });
        });
    }

    function teardownRoom(room) {
        console.log('Tearing down room ' + room);
        delete io.nsps['/' + room];
        delete roomNamespaces[room];
    }

    module.exports = {
        server: server,
        port: process.env.PORT || port
    };
}());<commit_msg>Add setup of rooms when server is restarted or scaled<commit_after>(function () {
    'use strict';
    // Dependencies
    const restify = require('restify');
    const socketio = require('socket.io');
    const redis = require('redis');
    const Promise = require('bluebird');
    const socketIORedis = require('socket.io-redis');

    // Setup Redis client with promises
    Promise.promisifyAll(redis.RedisClient.prototype);
    Promise.promisifyAll(redis.Multi.prototype);

    // Configuration
    const port = 8080;
    const burst = 100;
    const throttleRate = 50;

    var server = restify.createServer();
    var io = socketio.listen(server);
    var redisClient = redis.createClient({
        host: process.env.REDIS_HOST,
        port: process.env.REDIS_PORT
    });
    io.adapter(socketIORedis({host: process.env.REDIS_HOST, port: process.env.REDIS_PORT}));

    server.use(restify.CORS());
    server.use(restify.gzipResponse());
    server.use(restify.bodyParser());
    server.use(restify.throttle({
        burst: burst,
        rate: throttleRate,
        ip: true
    }));
    server.use(restify.conditionalRequest());

    // Health Check
    server.get('/', function (req, res) {
        res.status(200);
        res.send({
            message: 'Oh hai there!'
        });
    });

    var roomNamespaces = {};
    var defaultInstruments = {
        drums: false,
        bass: false,
        lead: false,
        rhythm: false
    };

    console.log('Setting up current rooms');
    redisClient
        .getAsync('rooms')
        .then(JSON.parse)
        .then(function (rooms) {
            rooms = rooms || [];

            rooms.forEach(function(room) {
                console.log('Setting up ' + room + ' from Redis');
               setupRoom(room);
            });
        });

    server.get('/flush', function (req, res) {
        console.log('Flushing Current State');
        redisClient
            .flushallAsync()
            .then(function () {
                res.status(204);
                res.end();
            });
    });

    server.get('/rooms', function (req, res, next) {
        console.log('Retrieving Room List');
        redisClient
            .getAsync('rooms')
            .then(JSON.parse)
            .then(function (rooms) {
                console.log('Got Room List');
                res.send(rooms || []);
            })
            .catch(next);
    });
    server.post('/rooms/:room', function (req, res, next) {
        let roomName = req.params.room;
        console.log('Creating Room ' + roomName);
        redisClient
            .getAsync('rooms')
            .then(JSON.parse)
            .then(function (rooms) {
                rooms = rooms || [];

                if (rooms.indexOf(roomName) >= 0) {
                    console.log('Room ' + roomName + ' already exists');
                    res.status(419);
                    return res.send({
                        name: 'RoomAlreadyExists',
                        message: 'The room ' + roomName + ' already exists',
                        statusCode: 419
                    });
                }

                rooms.push(roomName);

                console.log('Storing newly created room');
                return Promise.all([
                    redisClient.setAsync('rooms:' + roomName, JSON.stringify(defaultInstruments)),
                    redisClient.setAsync('rooms', JSON.stringify(rooms))
                ]).then(function () {
                    console.log('Room stored, setting it up');
                    setupRoom(roomName);
                    res.status(204);
                    res.end();
                });
            })
            .catch(next);
    });
    server.del('/rooms/:room', function (req, res) {
        let roomName = req.params.room;
        console.log('Removing Room ' + roomName);
        redisClient
            .getAsync('rooms')
            .then(JSON.parse)
            .then(function (rooms) {
                rooms = rooms || [];
                let roomIndex = rooms.indexOf(roomName);
                if (roomIndex >= 0) {
                    console.log('Room ' + roomName + ' exists, removing it');
                    rooms.splice(roomIndex, 1);
                    return Promise.all([
                        redisClient.delAsync('rooms:' + roomName),
                        redisClient.setAsync('rooms', JSON.stringify(rooms))
                    ]).then(function () {
                        teardownRoom(roomName);
                        console.log('Deleted room ' + roomName);
                        res.status(204);
                        res.end();
                    });
                }
                teardownRoom(roomName);
                res.status(404);
                res.send({
                    name: 'RoomNotFound',
                    message: 'The room ' + roomName + ' was not found',
                    statusCode: 404
                });
            });
    });

    server.get('/rooms/:room/instruments', function (req, res) {
        let roomName = req.params.room;
        console.log('Retrieving instruments for ' + roomName);
        redisClient
            .getAsync('rooms:' + roomName)
            .then(JSON.parse)
            .then(function (room) {
                if (!room) {
                    console.log('Room ' + roomName + 'doesn\'t exist');
                    res.status(404);
                    return res.send({
                        name: 'RoomNotFound',
                        message: 'The room ' + roomName + ' was not found',
                        statusCode: 404
                    });
                }

                console.log('Sending back instruments for room ' + roomName);
                res.send(room);
            });
    });

    server.post('/rooms/:room/instruments/:instrument', function (req, res) {
        let roomName = req.params.room;
        var instrumentName = req.params.instrument;
        console.log('Reserving ' + instrumentName + ' in ' + roomName);
        redisClient
            .getAsync('rooms:' + roomName)
            .then(JSON.parse)
            .then(function (room) {
                if (!room) {
                    console.log('Can\'t reserve ' + instrumentName + ' in ' + roomName + ' room doesn\'t exist');
                    res.status(404);
                    return res.send({
                        name: 'RoomNotFound',
                        message: 'The room ' + roomName + ' was not found',
                        statusCode: 404
                    });
                }

                if (!(instrumentName in room)) {
                    console.log('Can\'t reserve ' + instrumentName + ' in ' + roomName + ' instrument doesn\'t exist');
                    res.status(404);
                    return res.send({
                        name: 'InstrumentNotFound',
                        message: 'The instrument ' + instrumentName + ' was not found',
                        statusCode: 404
                    });
                } else if (room[instrumentName]) {
                    console.log('Can\'t reserve ' + instrumentName + ' in ' + roomName + ' instrument not available');
                    res.status(412);
                    return res.send({
                        name: 'InstrumentNotAvailable',
                        message: 'The instrument ' + instrumentName + ' has already been reserved',
                        statusCode: 412
                    });
                }

                room[instrumentName] = true;
                return redisClient
                    .setAsync('rooms:' + roomName, JSON.stringify(room))
                    .then(function () {
                        console.log('Instrument ' + instrumentName + ' in ' + roomName + ' reserved');
                        io.of('/' + roomName).emit('instrument reserved', instrumentName);
                        io.of('/' + roomName).emit('instruments changed', room);
                        res.status(204);
                        res.end();
                    });
            });
    });

    server.del('/rooms/:room/instruments/:instrument', function (req, res, next) {
        let roomName = req.params.room;
        var instrumentName = req.params.instrument;
        console.log('Releasing ' + instrumentName + ' in ' + roomName);
        releaseInstrument(roomName, instrumentName)
            .then(function () {
                console.log('Released ' + instrumentName + ' in ' + roomName + ' reserved');
                res.status(204);
                res.end();
            })
            .catch(function (reason) {
                console.log('Failed to release ' + instrumentName + ' in ' + roomName + ' because ' + reason);
                console.error(reason);
                res.status(reason.statusCode);
                return res.send(reason);
            });
    });

    server.listen(port, function () {
        console.log('socket.io server listening at %s', server.url);
    });

    function releaseInstrument(roomName, instrumentName) {
        console.log('Releasing Instrument ' + instrumentName + ' in ' + roomName);
        return redisClient
            .getAsync('rooms:' + roomName)
            .then(JSON.parse)
            .then(function (room) {
                if (!room) {
                    console.log('Failed Release ' + instrumentName + ' in ' + roomName + ' because room is not found');
                    return Promise.reject({
                        name: 'RoomNotFound',
                        message: 'The room ' + roomName + ' was not found',
                        statusCode: 404
                    });
                }

                if (!(instrumentName in room)) {
                    console.log('Failed Release ' + instrumentName + ' in ' + roomName + ' because instrument is not found');
                    return Promise.reject({
                        name: 'InstrumentNotFound',
                        message: 'The instrument ' + instrumentName + ' was not found',
                        statusCode: 404
                    });
                } else if (!room[instrumentName]) {
                    console.log('Failed Release ' + instrumentName + ' in ' + roomName + ' because instrument is not reserved');
                    return Promise.reject({
                        name: 'InstrumentNotReserved',
                        message: 'The instrument ' + instrumentName + ' has not yet been reserved',
                        statusCode: 412
                    });
                }

                room[instrumentName] = false;
                return redisClient
                    .setAsync('rooms:' + roomName, JSON.stringify(room))
                    .then(function () {

                        io.of('/' + roomName).emit('instrument released', instrumentName);
                        io.of('/' + roomName).emit('instruments changed', room);
                    })
                    .return(room);
            });
    }

    function setupRoom(roomName) {
        console.log('Setting up room ' + roomName);
        let socketInstruments = {};
        let nsp = io.of('/' + roomName);
        nsp.on('connection', function (socket) {
            console.log('Socket ' + socket.id + ' connected');

            socket.on('reserved instrument', function (instrument) {
                console.log('Instrument ' + instrument + ' has been confirmed reserved in ' + roomName);
                socketInstruments[socket.id] = instrument;
            });

            socket.on('disconnect', function () {
                console.log('Socket ' + socket.id + ' disconnected');
                // If the socket that disconnected has an instrument, release it
                if (socketInstruments[socket.id]) {
                    console.log('Releasing ' + socketInstruments[socket.id] + ' due to disconnect in ' + roomName);
                    releaseInstrument(roomName, socketInstruments[socket.id]);
                    delete socketInstruments[socket.id];
                }
            });

            Object.keys(defaultInstruments).forEach(function (instrument) {
                console.log('Setting up ' + instrument + ' for ' + roomName);
                socket.on('play ' + instrument, function (sound) {
                    console.log('Playing ' + sound + ' for ' + instrument + ' in ' + roomName);
                    io.of('/' + roomName).emit(instrument + ' played', sound);
                });
                socket.on('stop ' + instrument, function (sound) {
                    console.log('Stopping ' + sound + ' for ' + instrument + ' in ' + roomName);
                    io.of('/' + roomName).emit(instrument + ' stopped', sound);
                });
            });
        });
    }

    function teardownRoom(room) {
        console.log('Tearing down room ' + room);
        delete io.nsps['/' + room];
        delete roomNamespaces[room];
    }

    module.exports = {
        server: server,
        port: process.env.PORT || port
    };
}());<|endoftext|>


<commit_before>var TALKSTREAM = {};

TALKSTREAM.generateMessageElement = function(message) {
	return $('
')
		.attr({
			class: 'message ' + (message.userId == $("html").attr("data-me-id") ? 'me' : 'otherparty'),
			title: message.createdAt + '
via ' + message.app.name,
			'data-id': message.id,
			'data-user-id': message.userId,
			'data-user-color': message.user.color
		})
		.append(generateArticle());

	function generateArticle() {
		return $('
')
		.append(generateIcon())
		.append(generateContentContainer());

		function generateContentContainer() {
			return $('
')
			.append(message.userId == $("html").attr("data-me-id") ? generateDeleteButton() : null)
			.append(generateContent())
			.append(generateTime());

			function generateDeleteButton() {
				return $('<button class="deleteButton" role="button" title="メッセージを削除">')
				.append($(''));
			}

			function generateContent() {
				return $('
')
				.append($('
').html(parseText(message.text)))
				.append(message.isImageAttached ? generateImage() : null)

				function generateImage() {
					return $('')
					.attr('src', conf.url + '/img/talk-message/' + message.id);
				}
			}

			function generateTime() {
				return $('<time>')
				.attr('datetime', message.createdAt)
				.html(message.createdAt);
			}
		}

		function generateIcon() {
			return $('')
			.attr('href', conf.url + '/' + message.user.screenName)
			.attr('title', message.user.comment)
			.append(
			$('')
			.attr('src', conf.url + '/img/icon/' + message.user.screenName)
			);
		}
	}

	function parseText(text) {
		text = escapeHtml(text);
		text = parsePre(text);
		text = parseURL(text);
		text = parseReply(text);
		text = parseBold(text);
		text = parseSmall(text);
		text = parseNewLine(text);
		return text;

		function parsePre(text) {
			return text.replace(/'''(.+?)'''/g, function(_, word) {
				return '
' + word + '
';
			});
		}

		function parseURL(text) {
			return text.replace(/https?:\/\/[-_.!~*a-zA-Z0-9;\/?:\@&=+\$,%#]+/g, function(url) {
				return '' + url + '';
			});
		}

		function parseReply(text) {
			return text.replace(/@([a-zA-Z0-9_]+)/g, function(_, screenName) {
				return '@' + screenName + '';
			});
		}

		function parseBold(text) {
			return text.replace(/\*\*(.+?)\*\*/g, function(_, word) {
				return '' + word + '';
			});
		}

		function parseSmall(text) {
			return text.replace(/\(\((.+?)\)\)/g, function(_, word) {
				return '(' + word + ')';
			});
		}

		function parseNewLine(text) {
			return text.replace(/(\r\n|\r|\n)/g, '
');
		}
	}

	function escapeHtml(text) {
		return $('
').text(text).html();
	}
}

TALKSTREAM.setEvent = function($message) {
	var id = $message.attr('data-id');
	var userId = $message.attr('data-user-id');

	if (userId == $("html").attr("data-me-id")) {
		$message.find('.content').dblclick(function() {
			var $text = $message.find('.text');
			var text = $text.text();
			var $textarea = $('<textarea class="text">').text(text);
			$textarea.css({
				width: ($text.outerWidth() + 1) + 'px',
				height: ($text.outerHeight() + 1) + 'px'
			});
			$text.replaceWith($textarea);
			$textarea.focus();
			$textarea.change(function() {
				var text = $(this).val();
				var $textp = $('
').text(text);
				$textarea.replaceWith($textp);
				$.ajax('https://api.misskey.xyz/talk/fix', {
					type: 'put',
					data: { message_id: id, text: text },
					dataType: 'json',
					xhrFields: { withCredentials: true }
				}).done(function(data) {
				}).fail(function(data) {
				});
			});
			$textarea.blur(function() {
				var $textp = $('
').text(text);
				$textarea.replaceWith($textp);
			});
		});

		$message.find('.deleteButton').click(function() {
			$button = $(this);
			$button.attr('disabled', true);
			$.ajax('https://api.misskey.xyz/talk/delete', {
				type: 'delete',
				data: { message_id: id },
				dataType: 'json',
				xhrFields: { withCredentials: true }
			}).done(function(data) {
				$message.attr('data-is-deleted', 'true');
				$button.remove();
			}).fail(function(data) {
				$button.attr('disabled', false);
			});
		});
	}
}

$(function() {
	$("body").css("margin-bottom", $("#postFormContainer").outerHeight() + "px");
	scroll(0, $('html').outerHeight())

	socket = io.connect('https://api.misskey.xyz:1207/streaming/talk', { port: 1207 });

	socket.on('connected', function() {
		console.log('Connected');
		socket.json.emit('init', {
			'otherparty_id': $("html").attr("data-otherparty-id")
		});
	});

	socket.on('disconnect', function(client) {
		console.log('Disconnected');
	});

	socket.on('otherpartyEnterTheTalk', function(client) {
		console.log('相手が入室しました');
	});

	socket.on('otherpartyLeftTheTalk', function(client) {
		console.log('相手が退室しました');
	});

	socket.on('otherpartyMessage', function(message) {
		console.log('otherpartyMessage', message);
		new Audio('/resources/sounds/talk-message.mp3').play();
		if ($('#stream #otherpartyTyping')[0]) {
			$('#stream #otherpartyTyping').remove();
		}
		appendMessage(message);
		$.ajax('https://api.misskey.xyz/talk/read', {
			type: 'post',
			data: { message_id: message.id },
			dataType: 'json',
			xhrFields: { withCredentials: true }
		}).done(function(data) {
		}).fail(function(data) {
		});
	});

	socket.on('meMessage', function(message) {
		console.log('meMessage', message);
		new Audio('/resources/sounds/talk-message.mp3').play();
		appendMessage(message);
	});

	socket.on('otherpartyMessageUpdate', function(message) {
		console.log('otherpartyMessageUpdate', message);
		var $message = $('#stream > .messages').find('.message[data-id=' + message.id + ']');
		if ($message != null) {
			$message.find('.text').text(message.text);
		}
	});

	socket.on('meMessageUpdate', function(message) {
		console.log('meMessageUpdate', message);
		var $message = $('#stream > .messages').find('.message[data-id=' + message.id + ']');
		if ($message != null) {
			$message.find('.text').text(message.text);
		}
	});

	socket.on('otherpartyMessageDelete', function(id) {
		console.log('otherpartyMessageDelete', id);
		var $message = $('#stream > .messages').find('.message[data-id=' + id + ']');
		if ($message != null) {
			$message.find('.content').empty();
			$message.find('.content').append('
このメッセージは削除されました
');
		}
	});

	socket.on('meMessageDelete', function(id) {
		console.log('otherpartyMessageDelete', id);
		var $message = $('#stream > .messages').find('.message[data-id=' + id + ']');
		if ($message != null) {
			$message.find('.content').empty();
			$message.find('.content').append('
このメッセージは削除されました
');
		}
	});

	socket.on('alive', function() {
		console.log('alive');

		var $status = $('');
		$('#otherpartyStatus').prepend($status);
		scroll(0, $('html').outerHeight());
		setTimeout(function() {
			$status.remove();
		}, 6000);
	});

	socket.on('type', function(type) {
		console.log('type', type.text);
		if ($('#otherpartyStatus #otherpartyTyping')[0]) {
			$('#otherpartyStatus #otherpartyTyping').remove();
		}

		var $typing = $('
' + escapeHTML(type.text) + '
');
		$typing.appendTo($('#otherpartyStatus')).animate({
			opacity: 0
		}, 5000);
		scroll(0, $('html').outerHeight());
		setTimeout(function() {
			$typing.remove();
		}, 5000);
	});

	socket.emit('alive');
	setInterval(function() {
		socket.emit('alive');
	}, 5000);

	$('#postForm textarea').bind('input', function() {
		socket.json.emit('type', {
			'text': $('#postForm textarea').val()
		});
	});

	$('#postForm').find('.imageAttacher input[name=image]').change(function() {
		var $input = $(this);
		var file = $(this).prop('files')[0];
		if (!file.type.match('image.*')) return;
		var reader = new FileReader();
		reader.onload = function() {
			var $img = $('').attr('src', reader.result);
			$input.parent('.imageAttacher').find('p, img').remove();
			$input.parent('.imageAttacher').append($img);
		};
		reader.readAsDataURL(file);
	});

	$('#postForm').submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find('[type=submit]');

		$submitButton.attr('disabled', true);
		$submitButton.text('Updating...');

		$.ajax('https://api.misskey.xyz/talk/say', {
			type: 'post',
			processData: false,
			contentType: false,
			data: new FormData($form[0]),
			dataType: 'json',
			xhrFields: {
				withCredentials: true
			}
		}).done(function(data) {
			$form[0].reset();
			$form.find('textarea').focus();
			$form.find('.imageAttacher').find('p, img').remove();
			$form.find('.imageAttacher').append($('

'));
			$submitButton.attr('disabled', false);
			$submitButton.text('Update');
		}).fail(function(data) {
			$form[0].reset();
			$form.find('textarea').focus();
			/*alert('error');*/
			$submitButton.attr('disabled', false);
			$submitButton.text('Update');
		});
	});
});

$(window).load(function() {
	$("body").css("margin-bottom", $("#postFormContainer").outerHeight() + "px");
	scroll(0, document.body.clientHeight)
});

$(window).resize(function() {
	$("body").css("margin-bottom", $("#postFormContainer").outerHeight() + "px");
});

function appendMessage(message) {
	var $message = TALKSTREAM.generateMessageElement(message).hide();
	$message.appendTo($('#stream > .messages')).show(200);
	TALKSTREAM.setEvent($message);
	var animateTimer = setInterval(function() {
		scroll(0, $('html').outerHeight());
	}, 1);
	setTimeout(function() {
		clearInterval(animateTimer);
	}, 201);
}

$(function() {
	$('.messages .message.me').each(function() {
		TALKSTREAM.setEvent($(this));
	});
});<commit_msg>Fix typo<commit_after>var TALKSTREAM = {};

TALKSTREAM.generateMessageElement = function(message) {
	return $('
')
		.attr({
			class: 'message ' + (message.userId == $("html").attr("data-me-id") ? 'me' : 'otherparty'),
			title: message.createdAt + '
via ' + message.app.name,
			'data-id': message.id,
			'data-user-id': message.userId,
			'data-user-color': message.user.color
		})
		.append(generateArticle());

	function generateArticle() {
		return $('
')
		.append(generateIcon())
		.append(generateContentContainer());

		function generateContentContainer() {
			return $('
')
			.append(message.userId == $("html").attr("data-me-id") ? generateDeleteButton() : null)
			.append(generateContent())
			.append(generateTime());

			function generateDeleteButton() {
				return $('<button class="deleteButton" role="button" title="メッセージを削除">')
				.append($(''));
			}

			function generateContent() {
				return $('
')
				.append($('
').html(parseText(message.text)))
				.append(message.isImageAttached ? generateImage() : null)

				function generateImage() {
					return $('')
					.attr('src', conf.url + '/img/talk-message/' + message.id);
				}
			}

			function generateTime() {
				return $('<time>')
				.attr('datetime', message.createdAt)
				.html(message.createdAt);
			}
		}

		function generateIcon() {
			return $('')
			.attr('href', conf.url + '/' + message.user.screenName)
			.attr('title', message.user.comment)
			.append(
			$('')
			.attr('src', conf.url + '/img/icon/' + message.user.screenName)
			);
		}
	}

	function parseText(text) {
		text = escapeHtml(text);
		text = parsePre(text);
		text = parseURL(text);
		text = parseReply(text);
		text = parseBold(text);
		text = parseSmall(text);
		text = parseNewLine(text);
		return text;

		function parsePre(text) {
			return text.replace(/'''(.+?)'''/g, function(_, word) {
				return '
' + word + '
';
			});
		}

		function parseURL(text) {
			return text.replace(/https?:\/\/[-_.!~*a-zA-Z0-9;\/?:\@&=+\$,%#]+/g, function(url) {
				return '' + url + '';
			});
		}

		function parseReply(text) {
			return text.replace(/@([a-zA-Z0-9_]+)/g, function(_, screenName) {
				return '@' + screenName + '';
			});
		}

		function parseBold(text) {
			return text.replace(/\*\*(.+?)\*\*/g, function(_, word) {
				return '' + word + '';
			});
		}

		function parseSmall(text) {
			return text.replace(/\(\((.+?)\)\)/g, function(_, word) {
				return '(' + word + ')';
			});
		}

		function parseNewLine(text) {
			return text.replace(/(\r\n|\r|\n)/g, '
');
		}
	}

	function escapeHtml(text) {
		return $('
').text(text).html();
	}
}

TALKSTREAM.setEvent = function($message) {
	var id = $message.attr('data-id');
	var userId = $message.attr('data-user-id');

	if (userId == $("html").attr("data-me-id")) {
		$message.find('.content').dblclick(function() {
			var $text = $message.find('.text');
			var text = $text.text();
			var $textarea = $('<textarea class="text">').text(text);
			$textarea.css({
				width: ($text.outerWidth() + 1) + 'px',
				height: ($text.outerHeight() + 1) + 'px'
			});
			$text.replaceWith($textarea);
			$textarea.focus();
			$textarea.change(function() {
				var text = $(this).val();
				var $textp = $('
').text(text);
				$textarea.replaceWith($textp);
				$.ajax('https://api.misskey.xyz/talk/fix', {
					type: 'put',
					data: { message_id: id, text: text },
					dataType: 'json',
					xhrFields: { withCredentials: true }
				}).done(function(data) {
				}).fail(function(data) {
				});
			});
			$textarea.blur(function() {
				var $textp = $('
').text(text);
				$textarea.replaceWith($textp);
			});
		});

		$message.find('.deleteButton').click(function() {
			$button = $(this);
			$button.attr('disabled', true);
			$.ajax('https://api.misskey.xyz/talk/delete', {
				type: 'delete',
				data: { message_id: id },
				dataType: 'json',
				xhrFields: { withCredentials: true }
			}).done(function(data) {
				$message.attr('data-is-deleted', 'true');
				$button.remove();
			}).fail(function(data) {
				$button.attr('disabled', false);
			});
		});
	}
}

$(function() {
	$("body").css("margin-bottom", $("#postFormContainer").outerHeight() + "px");
	scroll(0, $('html').outerHeight())

	socket = io.connect('https://api.misskey.xyz:1207/streaming/talk', { port: 1207 });

	socket.on('connected', function() {
		console.log('Connected');
		socket.json.emit('init', {
			'otherparty_id': $("html").attr("data-otherparty-id")
		});
	});

	socket.on('disconnect', function(client) {
		console.log('Disconnected');
	});

	socket.on('otherpartyEnterTheTalk', function(client) {
		console.log('相手が入室しました');
	});

	socket.on('otherpartyLeftTheTalk', function(client) {
		console.log('相手が退室しました');
	});

	socket.on('otherpartyMessage', function(message) {
		console.log('otherpartyMessage', message);
		new Audio('/resources/sounds/talk-message.mp3').play();
		if ($('#stream #otherpartyTyping')[0]) {
			$('#stream #otherpartyTyping').remove();
		}
		appendMessage(message);
		$.ajax('https://api.misskey.xyz/talk/read', {
			type: 'post',
			data: { message_id: message.id },
			dataType: 'json',
			xhrFields: { withCredentials: true }
		}).done(function(data) {
		}).fail(function(data) {
		});
	});

	socket.on('meMessage', function(message) {
		console.log('meMessage', message);
		new Audio('/resources/sounds/talk-message.mp3').play();
		appendMessage(message);
	});

	socket.on('otherpartyMessageUpdate', function(message) {
		console.log('otherpartyMessageUpdate', message);
		var $message = $('#stream > .messages').find('.message[data-id=' + message.id + ']');
		if ($message != null) {
			$message.find('.text').text(message.text);
		}
	});

	socket.on('meMessageUpdate', function(message) {
		console.log('meMessageUpdate', message);
		var $message = $('#stream > .messages').find('.message[data-id=' + message.id + ']');
		if ($message != null) {
			$message.find('.text').text(message.text);
		}
	});

	socket.on('otherpartyMessageDelete', function(id) {
		console.log('otherpartyMessageDelete', id);
		var $message = $('#stream > .messages').find('.message[data-id=' + id + ']');
		if ($message != null) {
			$message.find('.content').empty();
			$message.find('.content').append('
このメッセージは削除されました
');
		}
	});

	socket.on('meMessageDelete', function(id) {
		console.log('otherpartyMessageDelete', id);
		var $message = $('#stream > .messages').find('.message[data-id=' + id + ']');
		if ($message != null) {
			$message.find('.content').empty();
			$message.find('.content').append('
このメッセージは削除されました
');
		}
	});

	socket.on('alive', function() {
		console.log('alive');

		var $status = $('');
		$('#otherpartyStatus').prepend($status);
		scroll(0, $('html').outerHeight());
		setTimeout(function() {
			$status.remove();
		}, 6000);
	});

	socket.on('type', function(type) {
		console.log('type', type.text);
		if ($('#otherpartyStatus #otherpartyTyping')[0]) {
			$('#otherpartyStatus #otherpartyTyping').remove();
		}

		var $typing = $('
' + escapeHTML(type.text) + '
');
		$typing.appendTo($('#otherpartyStatus')).animate({
			opacity: 0
		}, 5000);
		scroll(0, $('html').outerHeight());
		setTimeout(function() {
			$typing.remove();
		}, 5000);
	});

	socket.emit('alive');
	setInterval(function() {
		socket.emit('alive');
	}, 5000);

	$('#postForm textarea').bind('input', function() {
		socket.json.emit('type', {
			'text': $('#postForm textarea').val()
		});
	});

	$('#postForm').find('.imageAttacher input[name=image]').change(function() {
		var $input = $(this);
		var file = $(this).prop('files')[0];
		if (!file.type.match('image.*')) return;
		var reader = new FileReader();
		reader.onload = function() {
			var $img = $('').attr('src', reader.result);
			$input.parent('.imageAttacher').find('p, img').remove();
			$input.parent('.imageAttacher').append($img);
		};
		reader.readAsDataURL(file);
	});

	$('#postForm').submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find('[type=submit]');

		$submitButton.attr('disabled', true);
		$submitButton.text('Updating...');

		$.ajax('https://api.misskey.xyz/talk/say', {
			type: 'post',
			processData: false,
			contentType: false,
			data: new FormData($form[0]),
			dataType: 'json',
			xhrFields: {
				withCredentials: true
			}
		}).done(function(data) {
			$form[0].reset();
			$form.find('textarea').focus();
			$form.find('.imageAttacher').find('p, img').remove();
			$form.find('.imageAttacher').append($('

'));
			$submitButton.attr('disabled', false);
			$submitButton.text('Update');
		}).fail(function(data) {
			$form[0].reset();
			$form.find('textarea').focus();
			/*alert('error');*/
			$submitButton.attr('disabled', false);
			$submitButton.text('Update');
		});
	});
});

$(window).load(function() {
	$("body").css("margin-bottom", $("#postFormContainer").outerHeight() + "px");
	scroll(0, document.body.clientHeight)
});

$(window).resize(function() {
	$("body").css("margin-bottom", $("#postFormContainer").outerHeight() + "px");
});

function appendMessage(message) {
	var $message = TALKSTREAM.generateMessageElement(message).hide();
	$message.appendTo($('#stream > .messages')).show(200);
	TALKSTREAM.setEvent($message);
	var animateTimer = setInterval(function() {
		scroll(0, $('html').outerHeight());
	}, 1);
	setTimeout(function() {
		clearInterval(animateTimer);
	}, 201);
}

$(function() {
	$('.messages .message.me').each(function() {
		TALKSTREAM.setEvent($(this));
	});
});<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, IT Services, Stockholm University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of Stockholm University nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * The app view for the map module.
 *
 * @class A Backbone view to handle the app.
 * @author Joakim Lundin
 * @author Lucien Bokouka
 * @author Björn Westlin
 * @type {Backbone.View}
 */
suApp.view.AppView = Backbone.View.extend(
    /** @lends AppView */
    {

      /**
       * @constructs
       */
      initialize: function (options) {
        _.bindAll(this,
            "render",
            'locationCallback',
            'campusCallback',
            'menuSelectCallback',
            "startGPSPositioning",
            'handleZoomChanged',
            'handleDeviceReady'
        );

        $(document).on("deviceready.appview", this.handleDeviceReady);
        $(document).on("offline", this.handleNoNetworkConnectionMessage);

        var self = this;
        i18n.init({resGetPath: '../i18n/__lng__.json'}, function () {
          self.$el.i18n();
          $('#search-box').i18n();
        });

        this.title = options.title;
        this.mapModel = new suApp.model.MapModel();

        var filterByCampus = this.model.get('filterByCampus');
        var showMenu = this.model.get('menu');

        this.mapView = new suApp.view.MapView({
          el: $('#map_canvas'),
          model: this.mapModel,
          appModel: this.model,
          appView: this
        });

        this.searchView = new suApp.view.SearchView({
          el: $('#search-box'),
          collection: this.model.getFilterCollection(),
          placeholderSuffix: options.title ? options.title.toLowerCase() : undefined
        });

        this.searchView.on('selected', function (selectedElement) {
          if (filterByCampus) {
            self.campusCallback(selectedElement);
          }
          else {
            self.locationCallback(selectedElement);
          }
        });

        this.mapView.on('zoom_changed', this.handleZoomChanged);
        this.model.on('change:campus', this.changeCampus, this);
        this.model.locations.on("reset", function () {
          self.mapView.replacePoints(self.model.locations);
        });

        // Display a menu button
        if (showMenu) {
          this.menuPopupView = new suApp.view.MenuPopupView({
            el: $('#menupopup'),
            campuses: this.model.campuses,
            appModel: this.model,
            searchView: this.searchView
          });

          this.menuPopupView.on('selected', this.menuSelectCallback);

          this.changeCampus();
        }
      },

      handleNoNetworkConnectionMessage: function(){
        showError(i18n.t("error.connectionlost"));
      },

      /**
       * Registers events.
       */
      events: {
        "click #menubutton": "showMenu"
      },

      /**
       * Render the app module.
       */
      render: function () {
        $('div[data-role="header"] > h1 > span').attr('data-i18n', this.title);
        $('div[data-role="header"]').i18n();

        if (this.model.get('menu') === true) {
          $('div[data-role="header"]').append(JST['map/menu/button']);
          $('#menubutton').button();

          this.delegateEvents();
        }
        this.mapView.render();
      },

      /**
       * Remove handler for the view.
       */
      remove: function () {
        $(document).off('.appview');

        // Stop GPS positioning watch
        if (this.gpsWatchId && navigator.geolocation) {
          navigator.geolocation.clearWatch(this.gpsWatchId);
        }

        Backbone.View.prototype.remove.call(this);
      },

      /**
       * Handle selected model from search view.
       *
       * @param selectedModel the selected model
       */
      locationCallback: function (selectedModel) {
        if (selectedModel) {
          this.model.hideAllModelsExceptOne(selectedModel);
          selectedModel.trigger('click');
        }
        else {
          this.model.handleLocationsReset();
          this.mapView.infoWindowView.close();
        }
      },

      /**
       * Handle selected model from search view.
       *
       * @param selectedModel the selected model
       */
      campusCallback: function (selectedModel) {
        if (selectedModel) {
          this.model.set('campus', selectedModel);
        }
      },

      /**
       * Callback for menu selection
       *
       * @param campus the selected campus
       */
      menuSelectCallback: function (campus) {
        this.model.set('campus', campus);
      },

      /**
       * Handles the device ready event.
       */
      handleDeviceReady: function () {
        gaPlugin.trackPage(null, null, "map/index.html#" + Backbone.history.fragment);
        this.startGPSPositioning();
      },

      /**
       * Handle changed zoom level.
       *
       * @param zoom the new zoom level.
       */
      handleZoomChanged: function (zoom) {
        if (this.model.get('zoomSensitive') === true) {
          if (zoom >= suApp.config.map.zoom.threshold) {
            this.trigger('toggleMarkerVisibility', this.model.locations, true);
          }
          else if (zoom < suApp.config.map.zoom.threshold) {
            this.trigger('toggleMarkerVisibility', this.model.locations, false);
          }
        }
      },

      /**
       * Show the menu.
       */
      showMenu: function () {
        this.menuPopupView.render();
      },

      /**
       * Show all locations of a specific type.
       */
      // TODO Why do we need to call updateLocations twice initially?
      updateLocations: function () {
        this.model.fetchLocations();
      },

      /**
       * Moves map to selected campus & resets locations.
       */
      changeCampus: function () {
        var campus = this.model.get('campus');
        var lat = campus.getLat();
        var lng = campus.getLng();
        this.mapModel.setMapPosition(lat, lng);
        this.mapModel.setZoom(campus.getZoom());
      },

      getCurrentPosition: function(timeout, showErrorMessage) {
        // setting default value for timeout to 2000 ms
        var timeout = typeof timeout !== 'undefined'? timeout: 2000;
        // setting default value for showErrorMessage to false
        var showErrorMessage = typeof showErrorMessage !== 'undefined'? showErrorMessage: false;

        this.gpsWatchId = navigator.geolocation.getCurrentPosition(
            function (pos) {
              alert("start navigation");
              alert(pos.coords + ": " + pos.timestamp);
              self.mapView.trigger('updateCurrentPosition', pos);
            },
            function (error) {
              if (showErrorMessage) {
                if (device.platform == 'Android') {
                  showError(i18n.t("error.noGPSAndroid"));
                } else if (device.platform == 'iOS') {
                  showError(i18n.t("error.noGPSiOS"));
                }
              }
              alert("getPosition error: (" + error.code + ") " + error.message);
            },
            {frequency:500, maximumAge: 0, timeout: timeout, enableHighAccuracy:true}
        );
      },

      watchCurrentPosition: function() {
        this.gpsWatchId = navigator.geolocation.watchPosition(
            function (pos) {
//              alert("update navigation");
//              alert(pos.coords + ": " + pos.timestamp);
              self.mapView.trigger('updateCurrentPosition', pos);
            },
            function (error) {
              alert("updatePosition error: (" + error.code + ") " + error.message);
            },
            {frequency:500,maximumAge: 0, timeout: 2000, enableHighAccuracy:true}
        );
      },

      /**
       * Update the position from GPS.
       */
      startGPSPositioning: function () {
        if (navigator.geolocation) {
          var self = this;

          alert("inside startGPSPositioning: " + navigator.geolocation);
          // Get the current position or display error message
          this.gpsWatchId = this.getCurrentPosition();
          // Start watching for GPS position changes
          this.gpsWatchId = this.watchCurrentPosition();
        }
      }
    });
<commit_msg>MOB-311 Fixed position marker problem<commit_after>/*
 * Copyright (c) 2013, IT Services, Stockholm University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of Stockholm University nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * The app view for the map module.
 *
 * @class A Backbone view to handle the app.
 * @author Joakim Lundin
 * @author Lucien Bokouka
 * @author Björn Westlin
 * @type {Backbone.View}
 */
suApp.view.AppView = Backbone.View.extend(
    /** @lends AppView */
    {

      /**
       * @constructs
       */
      initialize: function (options) {
        _.bindAll(this,
            "render",
            'locationCallback',
            'campusCallback',
            'menuSelectCallback',
            "startGPSPositioning",
            'handleZoomChanged',
            'handleDeviceReady'
        );

        $(document).on("deviceready.appview", this.handleDeviceReady);
        $(document).on("offline", this.handleNoNetworkConnectionMessage);

        var self = this;
        i18n.init({resGetPath: '../i18n/__lng__.json'}, function () {
          self.$el.i18n();
          $('#search-box').i18n();
        });

        this.title = options.title;
        this.mapModel = new suApp.model.MapModel();

        var filterByCampus = this.model.get('filterByCampus');
        var showMenu = this.model.get('menu');

        this.mapView = new suApp.view.MapView({
          el: $('#map_canvas'),
          model: this.mapModel,
          appModel: this.model,
          appView: this
        });

        this.searchView = new suApp.view.SearchView({
          el: $('#search-box'),
          collection: this.model.getFilterCollection(),
          placeholderSuffix: options.title ? options.title.toLowerCase() : undefined
        });

        this.searchView.on('selected', function (selectedElement) {
          if (filterByCampus) {
            self.campusCallback(selectedElement);
          }
          else {
            self.locationCallback(selectedElement);
          }
        });

        this.mapView.on('zoom_changed', this.handleZoomChanged);
        this.model.on('change:campus', this.changeCampus, this);
        this.model.locations.on("reset", function () {
          self.mapView.replacePoints(self.model.locations);
        });

        // Display a menu button
        if (showMenu) {
          this.menuPopupView = new suApp.view.MenuPopupView({
            el: $('#menupopup'),
            campuses: this.model.campuses,
            appModel: this.model,
            searchView: this.searchView
          });

          this.menuPopupView.on('selected', this.menuSelectCallback);

          this.changeCampus();
        }
      },

      handleNoNetworkConnectionMessage: function(){
        showError(i18n.t("error.connectionlost"));
      },

      /**
       * Registers events.
       */
      events: {
        "click #menubutton": "showMenu"
      },

      /**
       * Render the app module.
       */
      render: function () {
        $('div[data-role="header"] > h1 > span').attr('data-i18n', this.title);
        $('div[data-role="header"]').i18n();

        if (this.model.get('menu') === true) {
          $('div[data-role="header"]').append(JST['map/menu/button']);
          $('#menubutton').button();

          this.delegateEvents();
        }
        this.mapView.render();
      },

      /**
       * Remove handler for the view.
       */
      remove: function () {
        $(document).off('.appview');

        // Stop GPS positioning watch
        if (this.gpsWatchId && navigator.geolocation) {
          navigator.geolocation.clearWatch(this.gpsWatchId);
        }

        Backbone.View.prototype.remove.call(this);
      },

      /**
       * Handle selected model from search view.
       *
       * @param selectedModel the selected model
       */
      locationCallback: function (selectedModel) {
        if (selectedModel) {
          this.model.hideAllModelsExceptOne(selectedModel);
          selectedModel.trigger('click');
        }
        else {
          this.model.handleLocationsReset();
          this.mapView.infoWindowView.close();
        }
      },

      /**
       * Handle selected model from search view.
       *
       * @param selectedModel the selected model
       */
      campusCallback: function (selectedModel) {
        if (selectedModel) {
          this.model.set('campus', selectedModel);
        }
      },

      /**
       * Callback for menu selection
       *
       * @param campus the selected campus
       */
      menuSelectCallback: function (campus) {
        this.model.set('campus', campus);
      },

      /**
       * Handles the device ready event.
       */
      handleDeviceReady: function () {
        gaPlugin.trackPage(null, null, "map/index.html#" + Backbone.history.fragment);
        this.startGPSPositioning();
      },

      /**
       * Handle changed zoom level.
       *
       * @param zoom the new zoom level.
       */
      handleZoomChanged: function (zoom) {
        if (this.model.get('zoomSensitive') === true) {
          if (zoom >= suApp.config.map.zoom.threshold) {
            this.trigger('toggleMarkerVisibility', this.model.locations, true);
          }
          else if (zoom < suApp.config.map.zoom.threshold) {
            this.trigger('toggleMarkerVisibility', this.model.locations, false);
          }
        }
      },

      /**
       * Show the menu.
       */
      showMenu: function () {
        this.menuPopupView.render();
      },

      /**
       * Show all locations of a specific type.
       */
      // TODO Why do we need to call updateLocations twice initially?
      updateLocations: function () {
        this.model.fetchLocations();
      },

      /**
       * Moves map to selected campus & resets locations.
       */
      changeCampus: function () {
        var campus = this.model.get('campus');
        var lat = campus.getLat();
        var lng = campus.getLng();
        this.mapModel.setMapPosition(lat, lng);
        this.mapModel.setZoom(campus.getZoom());
      },

      getCurrentPosition: function(timeout, showErrorMessage) {
        var self = this;

        // setting default value for timeout to 2000 ms
        var timeout = typeof timeout !== 'undefined'? timeout: 2000;
        // setting default value for showErrorMessage to false
        var showErrorMessage = typeof showErrorMessage !== 'undefined'? showErrorMessage: false;

        this.gpsWatchId = navigator.geolocation.getCurrentPosition(
            function (pos) {
              alert("start navigation");
              alert(pos.coords + ": " + pos.timestamp);
              self.mapView.trigger('updateCurrentPosition', pos);
            },
            function (error) {
              if (showErrorMessage) {
                if (device.platform == 'Android') {
                  showError(i18n.t("error.noGPSAndroid"));
                } else if (device.platform == 'iOS') {
                  showError(i18n.t("error.noGPSiOS"));
                }
              }
              alert("getPosition error: (" + error.code + ") " + error.message);
            },
            {frequency:500, maximumAge: 0, timeout: timeout, enableHighAccuracy:true}
        );
      },

      watchCurrentPosition: function() {
        var self = this;

        this.gpsWatchId = navigator.geolocation.watchPosition(
            function (pos) {
//              alert("update navigation");
//              alert(pos.coords + ": " + pos.timestamp);
              self.mapView.trigger('updateCurrentPosition', pos);
            },
            function (error) {
              alert("updatePosition error: (" + error.code + ") " + error.message);
            },
            {frequency:500,maximumAge: 0, timeout: 2000, enableHighAccuracy:true}
        );
      },

      /**
       * Update the position from GPS.
       */
      startGPSPositioning: function () {
        if (navigator.geolocation) {
          alert("inside startGPSPositioning: " + navigator.geolocation);
          // Get the current position or display error message
          this.gpsWatchId = this.getCurrentPosition();
          // Start watching for GPS position changes
          this.gpsWatchId = this.watchCurrentPosition();
        }
      }
    });
<|endoftext|>


<commit_before>'use strict';

console.log('Clear a timeout with a given ID:');

const timeoutId = setTimeout(() => {
  console.log('Should never show');
}, 500);

clearTimeout(timeoutId);
console.log('(Nothing should appear)');

console.log('\nClear timeouts via a setTimeout override:');

let globalObject;
if (typeof window === 'undefined') {
  globalObject = global;
} else {
  globalObject = window;
}

let allTimeoutIds = [];
const originalTimeout = setTimeout;
// Use a function instead of () => to ensure this can be overridden.
globalObject.setTimeout = function(callback, timeInMS) {
  const timeoutId = originalTimeout(callback, timeInMS);
  allTimeoutIds.push(timeoutId);
};

const originalClearTimeout = clearTimeout;
globalObject.clearTimeout = function(timeoutId) {
  allTimeoutIds = allTimeoutIds.filter((id) => id !== timeoutId);
  originalClearTimeout(timeoutId);
};

// Somewhere much later in code...

setTimeout(() => {
  console.log('Should never show 2');
}, 300);

setTimeout(() => {
  console.log('Should never show 3');
}, 400);

for (const id of allTimeoutIds) {
  clearTimeout(id);
}
console.log(allTimeoutIds)
// []

globalObject.setTimeout = originalTimeout;
globalObject.clearTimeout = clearTimeout;
console.log('\nClear timeouts via a global function:');
if (typeof window === 'undefined') {
  console.log('Not supported outside browser code.');
  return false;
}

function createClearAllTimeouts() {
  const noop = () => {};
  let firstId = setTimeout(noop, 0);

  return () => {
    const lastId = setTimeout(noop, 0);
    while (firstId !== lastId) {
      firstId += 1;
      clearTimeout(firstId);
    }
  };
};
const clearAllTimeouts = createClearAllTimeouts();

setTimeout(() => {
  console.log('Should never show 4');
}, 300);

setTimeout(() => {
  console.log('Should never show 5');
}, 400);

clearAllTimeouts();

<commit_msg>(doc) Added Stack Overflow author attribution to part of code<commit_after>'use strict';

console.log('Clear a timeout with a given ID:');

const timeoutId = setTimeout(() => {
  console.log('Should never show');
}, 500);

clearTimeout(timeoutId);
console.log('(Nothing should appear)');

console.log('\nClear timeouts via a setTimeout override:');

let globalObject;
if (typeof window === 'undefined') {
  globalObject = global;
} else {
  globalObject = window;
}

let allTimeoutIds = [];
const originalTimeout = setTimeout;
// Use a function instead of () => to ensure this can be overridden.
globalObject.setTimeout = function(callback, timeInMS) {
  const timeoutId = originalTimeout(callback, timeInMS);
  allTimeoutIds.push(timeoutId);
};

const originalClearTimeout = clearTimeout;
globalObject.clearTimeout = function(timeoutId) {
  allTimeoutIds = allTimeoutIds.filter((id) => id !== timeoutId);
  originalClearTimeout(timeoutId);
};

// Somewhere much later in code...

setTimeout(() => {
  console.log('Should never show 2');
}, 300);

setTimeout(() => {
  console.log('Should never show 3');
}, 400);

for (const id of allTimeoutIds) {
  clearTimeout(id);
}
console.log(allTimeoutIds)
// []

globalObject.setTimeout = originalTimeout;
globalObject.clearTimeout = clearTimeout;
console.log('\nClear timeouts via a global function:');
if (typeof window === 'undefined') {
  console.log('Not supported outside browser code.');
  return false;
}

// Syntax slightly modified from a Stack Overflow answer:
// https://stackoverflow.com/questions/8860188/javascript-clear-all-timeouts/16440036#16440036
function createClearAllTimeouts() {
  const noop = () => {};
  let firstId = setTimeout(noop, 0);

  return () => {
    const lastId = setTimeout(noop, 0);
    while (firstId !== lastId) {
      firstId += 1;
      clearTimeout(firstId);
    }
  };
};
const clearAllTimeouts = createClearAllTimeouts();

setTimeout(() => {
  console.log('Should never show 4');
}, 300);

setTimeout(() => {
  console.log('Should never show 5');
}, 400);

clearAllTimeouts();

<|endoftext|>


<commit_before>function vertexShader(attributes)
{
	var position = attributes[0];

	position[3] = 1;
	position = mat4.transform(this.worldMatrix, position);
	position = mat4.transform(this.viewMatrix, position);
	position = mat4.transform(this.projectionMatrix, position);
	position = mat4.transform(this.viewportMatrix, position);

	attributes[0] = position;

	return attributes;
}

function texture2D(textureData, u, v)
{
	var i = Math.floor(textureData.height * v) % textureData.height;
	var j = Math.floor(textureData.width * u) % textureData.width;
	var pixelIndex = i * textureData.width * 4 + j * 4;
	return textureData.data.slice(pixelIndex, pixelIndex + 4);
}

function pixelShader(varyings)
{
	var uv = varyings[2];
	var diffuse = texture2D(this.textureData, uv[0], uv[1]);
	return diffuse;
}
<commit_msg>IE doesn't support Float32Array.slice<commit_after>function vertexShader(attributes)
{
	var position = attributes[0];

	position[3] = 1;
	position = mat4.transform(this.worldMatrix, position);
	position = mat4.transform(this.viewMatrix, position);
	position = mat4.transform(this.projectionMatrix, position);
	position = mat4.transform(this.viewportMatrix, position);

	attributes[0] = position;

	return attributes;
}

function texture2D(textureData, u, v)
{
	var i = Math.floor(textureData.height * v) % textureData.height;
	var j = Math.floor(textureData.width * u) % textureData.width;
	var pixelIndex = i * textureData.width * 4 + j * 4;
	return vec4.fromValues(textureData.data[pixelIndex], textureData.data[pixelIndex + 1], textureData.data[pixelIndex + 2], 1);
}

function pixelShader(varyings)
{
	var uv = varyings[2];
	var diffuse = texture2D(this.textureData, uv[0], uv[1]);
	return diffuse;
}
<|endoftext|>