<commit_before>import Phaser from 'phaser'

import Boss from '../sprites/Boss'
import Player from '../sprites/Player'

import { enableMusicForState } from '../utils'

export default class extends Phaser.State {
  init (tilemap) {
    this.tilemap = tilemap

    if (tilemap === 'earth_fight') {
      this.stage.backgroundColor = '#3598db'
    }
  }

  create () {
    this.game.world.enableBody = true
    this.game.physics.startSystem(Phaser.Physics.ARCADE)
    this.game.curve.setPoints([50, 0, 0, 0, 50])

    this.disableMusic = enableMusicForState('ambient', this)

    this.map = this.game.add.tilemap(this.tilemap)
    this.map.addTilesetImage('lofi_environment_4x', 'tiles_lofi_environment')

    // Add both the background and ground layers. We won't be doing anything
    // with the GroundLayer though
    this.backgroundLayer = this.map.createLayer('backgroundlayer')
    this.groundLayer = this.map.createLayer('groundlayer')

    // Change the world size to match the size of this layer
    this.groundLayer.resizeWorld()

    // Before you can use the collide function you need to set what tiles can collide
    this.map.setCollisionBetween(1, 1000, true, 'groundlayer')

    // Add the sprite to the game and enable arcade physics on it
    this.player = new Player(this.game, 16, this.game.world.centerY)
    this.world.add(this.player)

    // Player physics in this state.
    this.player.body.collideWorldBounds = true
    this.player.body.velocity.x = 500 // Player is flying in from orbit.
    this.player.body.maxVelocity.x = 500
    this.player.body.bounce.y = 0.3
    this.player.body.gravity.y = 2000

    var bossSpawnX = this.game.world.centerX + this.game.world.centerX / 2
    this.boss = new Boss(this.game, this.player, bossSpawnX, this.game.world.height - 90)
    this.world.add(this.boss)

    // Make the camera follow the player.
    this.game.camera.follow(this.player)

    this.game.scale.pageAlignHorizontally = true
    this.game.scale.pageAlignVertically = true
    this.game.scale.refresh()

    this.game.time.advancedTiming = true

    if (this.tilemap === 'moon_fight') {

      // Hack for game start.

      var style = {
        font: "50px Arial",
        fill: "#F5DEB3",
        backgroundColor: '#8B4513',
      };

      this.title = this.game.add.text(0, -100, "  COBRA CALIBER 2  ", style);
      this.title.setShadow(3, 3, 'rgba(0,0,0,0.5)', 2);
      this.title.strokeThickness = 5;

      this.title.y = 50;
      this.title.x = this.game.width / 2 - this.title.width / 2;

      style = {
        font: "20px Arial",
        fill: "#F5DEB3",
        backgroundColor: '#8B4513',
      };

      this.subtitle = this.game.add.text(0, -100, "  THERE CAN ONLY BE ONE MORE  ", style);
      this.subtitle.setShadow(3, 3, 'rgba(0,0,0,0.5)', 2);
      this.subtitle.strokeThickness = 5;

      this.subtitle.y = this.title.y + 90;
      this.subtitle.x = this.game.width / 2 - this.subtitle.width / 2;

      this.player.body.velocity.x = 0

      this.player.x = this.game.world.centerX - this.game.world.centerX / 2
      this.player.y = this.game.world.height - 80

      var player = this.player
      var boss = this.boss

      player.say('I have been looking for you for a long time, father', function () {
        boss.say('I left you to die in that pit. How did you survive?', function () {
          player.say('That should be the least of your concerns, old man', function () {
            player.say('Time to die', function () {})
          })
        })
      })
    }
  }

  update () {
    // Make the sprite collide with the ground layer
    this.game.physics.arcade.collide(this.player, this.groundLayer)
    this.game.physics.arcade.collide(this.boss, this.groundLayer)

    // Jump when on the floor.
    if (this.player.isMovingUp() && this.player.body.onFloor()) {
      this.player.body.velocity.y = -800
    }

    // Horizontal air control is slower than ground.
    const accX = this.player.body.onFloor() ? 450 : 50
    if (this.player.isMovingRight()) {
      this.player.scale.setTo(1, 1)
      this.player.body.velocity.x += accX
    } else if (this.player.isMovingLeft()) {
      this.player.scale.setTo(-1, 1)
      this.player.body.velocity.x -= accX
    } else if (this.player.body.onFloor()) {
      this.player.body.velocity.x /= 2 // Break to a halt.
    }
  }

  render () {
    this.game.debug.text(this.time.fps, 10, 20, '#00ff00')
    this.game.debug.text(this.game.deathCounter, 980, 20, '#00ff00')
  }

  shutdown () {
    this.disableMusic()
  }
}
<commit_msg>start button<commit_after>import Phaser from 'phaser'

import Boss from '../sprites/Boss'
import Player from '../sprites/Player'

import { enableMusicForState } from '../utils'

export default class extends Phaser.State {
  init (tilemap) {
    this.tilemap = tilemap

    if (tilemap === 'earth_fight') {
      this.stage.backgroundColor = '#3598db'
    }
  }

  create () {
    this.game.world.enableBody = true
    this.game.physics.startSystem(Phaser.Physics.ARCADE)
    this.game.curve.setPoints([50, 0, 0, 0, 50])

    this.disableMusic = enableMusicForState('ambient', this)

    this.map = this.game.add.tilemap(this.tilemap)
    this.map.addTilesetImage('lofi_environment_4x', 'tiles_lofi_environment')

    // Add both the background and ground layers. We won't be doing anything
    // with the GroundLayer though
    this.backgroundLayer = this.map.createLayer('backgroundlayer')
    this.groundLayer = this.map.createLayer('groundlayer')

    // Change the world size to match the size of this layer
    this.groundLayer.resizeWorld()

    // Before you can use the collide function you need to set what tiles can collide
    this.map.setCollisionBetween(1, 1000, true, 'groundlayer')

    // Add the sprite to the game and enable arcade physics on it
    this.player = new Player(this.game, 16, this.game.world.centerY)
    this.world.add(this.player)

    // Player physics in this state.
    this.player.body.collideWorldBounds = true
    this.player.body.velocity.x = 500 // Player is flying in from orbit.
    this.player.body.maxVelocity.x = 500
    this.player.body.bounce.y = 0.3
    this.player.body.gravity.y = 2000

    var bossSpawnX = this.game.world.centerX + this.game.world.centerX / 2
    this.boss = new Boss(this.game, this.player, bossSpawnX, this.game.world.height - 90)
    this.world.add(this.boss)

    // Make the camera follow the player.
    this.game.camera.follow(this.player)

    this.game.scale.pageAlignHorizontally = true
    this.game.scale.pageAlignVertically = true
    this.game.scale.refresh()

    this.game.time.advancedTiming = true

    if (this.tilemap === 'moon_fight') {

      // Hack for game start.

      var style = {
        font: "50px Arial",
        fill: "#F5DEB3",
        backgroundColor: '#8B4513',
      };

      this.title = this.game.add.text(0, -100, "  COBRA CALIBER 2  ", style);
      this.title.setShadow(3, 3, 'rgba(0,0,0,0.5)', 2);
      this.title.strokeThickness = 5;

      this.title.y = 50;
      this.title.x = this.game.width / 2 - this.title.width / 2;

      style = {
        font: "20px Arial",
        fill: "#F5DEB3",
        backgroundColor: '#8B4513',
      };

      this.subtitle = this.game.add.text(0, -100, "  THERE CAN ONLY BE ONE MORE  ", style);
      this.subtitle.setShadow(3, 3, 'rgba(0,0,0,0.5)', 2);
      this.subtitle.strokeThickness = 5;

      this.subtitle.y = this.title.y + 90;
      this.subtitle.x = this.game.width / 2 - this.subtitle.width / 2;

      this.player.body.velocity.x = 0

      this.player.x = this.game.world.centerX - this.game.world.centerX / 2
      this.player.y = this.game.world.height - 80

      var LabelButton = function(game, x, y, key, label, callback, callbackContext, overFrame, outFrame, downFrame, upFrame) {
        Phaser.Button.call(this, game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame);
        // Style how you wish...
        this.style = { 'font': '40px Arial', 'fill': 'white', 'backgroundColor': 'magenta' };
        this.anchor.setTo( 0.5, 0.5 );
        this.label = new Phaser.Text(game, 0, 0, label, this.style);
        // Puts the label in the center of the button
        this.label.anchor.setTo( 0.5, 0.5 );
        this.addChild(this.label);
        this.setLabel( label );
        // Adds button to game
        game.add.existing(this);
      };

      LabelButton.prototype = Object.create(Phaser.Button.prototype);LabelButton.prototype.constructor = LabelButton;
      LabelButton.prototype.setLabel = function(label) {
          this.label.setText(label);
      };

      let y = this.subtitle.y + 150;

      this.startButton = new LabelButton(this.game, 0, y, null, " START GAME ", this.onStartClick, this, 1, 0, 2);
      this.startButton.x = this.game.width / 2 - this.startButton.width / 2 + 10;
      this.startButton.strokeThickness = 3;

    }
  }

  onStartClick () {

    this.startButton.destroy();

    var player = this.player
    var boss = this.boss

    setTimeout(function() {
      player.say('I have been looking for you for a long time, father', function () {
        boss.say('I left you to die in that pit. How did you survive?', function () {
          player.say('That should be the least of your concerns, old man', function () {
            player.say('Time to die', function () {})
          })
        })
      })
    }, 600)

  }

  update () {
    // Make the sprite collide with the ground layer
    this.game.physics.arcade.collide(this.player, this.groundLayer)
    this.game.physics.arcade.collide(this.boss, this.groundLayer)

    // Jump when on the floor.
    if (this.player.isMovingUp() && this.player.body.onFloor()) {
      this.player.body.velocity.y = -800
    }

    // Horizontal air control is slower than ground.
    const accX = this.player.body.onFloor() ? 450 : 50
    if (this.player.isMovingRight()) {
      this.player.scale.setTo(1, 1)
      this.player.body.velocity.x += accX
    } else if (this.player.isMovingLeft()) {
      this.player.scale.setTo(-1, 1)
      this.player.body.velocity.x -= accX
    } else if (this.player.body.onFloor()) {
      this.player.body.velocity.x /= 2 // Break to a halt.
    }
  }

  render () {
    this.game.debug.text(this.time.fps, 10, 20, '#00ff00')
    this.game.debug.text(this.game.deathCounter, 980, 20, '#00ff00')
  }

  shutdown () {
    this.disableMusic()
  }
}
<|endoftext|>


<commit_before>/**
 * Created by matvij on 21.06.17.
 */

define(['app', 'scripts/webitel/utils'], function (app, utils) {
    app.factory('WidgetModel', ["webitel", function (webitel) {

        function list(option, cb) {
            if (!option.domain)
                return cb(new Error("Domain is required."));

            webitel.api('GET', '/api/v2/widget' + buildQuery(option), cb);
        }

        function buildQuery (option) {
            var res = "?";
            angular.forEach(option, function (val, key) {
                res += key + '=' + val + '&'
            });
            return res.substring(0, res.length - 1);
        };

        function add(data, domain, cb) {

            if (!domain)
                return cb(new Error("Bad domain"));

            if (!data.name)
                return cb(new Error("Name is required"));

            if (!data.queue_id)
                return cb(new Error("Queue is required"));

            if (!data.config||!data.config.calendar||data.config.calendar.accept.length==0)
                return cb(new Error("Calendar is required"));

            if (!data.callflow_id)
                return cb(new Error("Number is required"));

            data.domain = domain;
            delete data._new;
            webitel.api('POST', '/api/v2/widget?domain=' + domain, data, cb);
        };

        function update(data, widgetId, domain, cb) {

            if (!domain)
                return cb(new Error("Bad domain"));

            if (!data.name)
                return cb(new Error("Name is required"));

            if (!data.queue_id)
                return cb(new Error("Queue is required"));

            if (!data.config||!data.config.calendar||data.config.calendar.accept.length==0)
                return cb(new Error("Calendar is required"));

            if (!data.callflow_id)
                return cb(new Error("Number is required"));

            data.domain = domain;
            webitel.api('PUT', '/api/v2/widget/'+widgetId+'?domain=' + domain, data, cb);
        };

        function item (id, domain, cb) {
            if (!id)
                return cb(new Error("Id is required."));

            if (!domain)
                return cb(new Error("Domain is required."));

            webitel.api('GET', '/api/v2/widget/' + id + '?domain=' + domain, function (err, res) {
                if (err)
                    return cb(err);
                var widget = res && res.data;
                return cb(null, widget);
            })
        }

        function remove (id, domain, cb) {
            if (!domain)
                return cb(new Error("Domain is required."));

            if (!id)
                return cb(new Error("Id is required."));
            webitel.api('DELETE', '/api/v2/widget/' + id + '?domain=' + domain, cb);
        };

        return {
            remove: remove,
            add: add,
            update: update,
            list: list,
            item: item
        }
    }])
})<commit_msg>WTEL-701<commit_after>/**
 * Created by matvij on 21.06.17.
 */

define(['app', 'scripts/webitel/utils'], function (app, utils) {
    app.factory('WidgetModel', ["webitel", function (webitel) {

        function list(option, cb) {
            if (!option.domain)
                return cb(new Error("Domain is required."));

            webitel.api('GET', '/api/v2/widget' + buildQuery(option), cb);
        }

        function buildQuery (option) {
            var res = "?";
            angular.forEach(option, function (val, key) {
                res += key + '=' + val + '&'
            });
            return res.substring(0, res.length - 1);
        };

        function add(data, domain, cb) {

            if (!domain)
                return cb(new Error("Bad domain"));

            if (!data.name)
                return cb(new Error("Name is required"));

            if (!data.queue_id)
                return cb(new Error("Queue is required"));

            if (!data.config||!data.config.calendar||data.config.calendar.accept.length==0)
                return cb(new Error("Calendar is required"));

            if (!data.callflow_id)
                return cb(new Error("Number is required"));

            data.domain = domain;
            delete data._new;
            webitel.api('POST', '/api/v2/widget?domain=' + domain, data, cb);
        };

        function update(data, widgetId, domain, cb) {

            if (!domain)
                return cb(new Error("Bad domain"));

            if (!data.name)
                return cb(new Error("Name is required"));

            if (!data.queue_id)
                return cb(new Error("Queue is required"));

            if (!data.config||!data.config.calendar||data.config.calendar.accept.length==0)
                return cb(new Error("Calendar is required"));

            if (!data.callflow_id)
                return cb(new Error("Number is required"));

            data.domain = domain;
            webitel.api('PUT', '/api/v2/widget/'+widgetId+'?domain=' + domain, data, cb);
        };

        function item (id, domain, cb) {
            if (!id)
                return cb(new Error("Id is required."));

            webitel.api('GET', '/api/v2/widget/' + id + '?domain=' + domain, function (err, res) {
                if (err)
                    return cb(err);
                var widget = res && res.data;
                return cb(null, widget);
            })
        }

        function remove (id, domain, cb) {
            if (!domain)
                return cb(new Error("Domain is required."));

            if (!id)
                return cb(new Error("Id is required."));
            webitel.api('DELETE', '/api/v2/widget/' + id + '?domain=' + domain, cb);
        };

        return {
            remove: remove,
            add: add,
            update: update,
            list: list,
            item: item
        }
    }])
})<|endoftext|>


<commit_before>/**
 * ownCloud - ocsms
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Loic Blot <loic.blot@unix-experience.fr>
 * @copyright Loic Blot 2014-2015
 */

// Some global vars to improve performances
var selectedConversation = null;
var curPhoneNumber = null;
var curContactName = '';
var lastMsgDate = 0;
var unreadCountCurrentConv = 0;
var unreadCountAllConv = 0;
var unreadCountNotifStep = 12;
var lastUnreadCountAllConv = 0;
var originalTitle = document.title;

var app = angular.module('OcSms', []);

function inArray(val, arr) {
	return ($.inArray(val, arr) != -1);
}

function arrayUnique(arr) {
	unq = arr.filter(function(item, i, arr) {
		return i == arr.indexOf(item);
	})
	return unq;
}

app.controller('OcSmsController', ['$scope',
	function ($scope) {
		$scope.buttons = [
			{text: "Send"}
		];
		$scope.contacts = [];
		$scope.sendCountry = function () {
			$.post(OC.generateUrl('/apps/ocsms/set/country'),{'country': $('select[name=intl_phone]').val()});
		};
		$scope.loadConversation = function (contact) {
			OC.Util.History.pushState('phonenumber=' + contact.nav);

			// phoneNumber must exist
			if (contact.nav !== null) {
				fetchConversation(contact.nav);
				changeSelectedConversation($("a[mailbox-navigation='" + contact.nav + "']"));
			}
		};

		$scope.addContact = function (ct) {
			$scope.$apply(function () {
				$scope.contacts.push(ct);
			});
		};
	}
]);

$.urlParam = function(name){
	var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
	if (results == null) {
		return null;
	}
	else {
		return results[1] || 0;
	}
};

var refreshConversation = function() {
	// if no conversation selected, then don't fetch page
	if (curPhoneNumber == null) {
		if ($('#app-content-header').is(':visible')) {
			$('#app-content-header').hide();
		}
		return;
	}
	$.getJSON(OC.generateUrl('/apps/ocsms/get/conversation'),
		{
			'phoneNumber': curPhoneNumber,
			"lastDate": lastMsgDate
		},
		function(jsondata, status) {
			var fmt = formatConversation(jsondata);
			conversationBuf = fmt[1];
			if (conversationBuf != '') {
				$('.msg-endtag').before(conversationBuf);
				$('#app-content').scrollTop(1E10);
				// This will blink the tab because there is new messages
				if (document.hasFocus() == false) {
					unreadCountCurrentConv += fmt[0];
					document.title = originalTitle + " (" + unreadCountCurrentConv + ")";
					desktopNotify(unreadCountCurrentConv + " unread message(s) in conversation with " + curContactName);
				}
			}

			setMessageCountInfo(jsondata);

			if ($('#app-content-header').is(':hidden')) {
				$('#app-content-header').show();
			}
		}
	);
};

var checkNewMessages = function() {
	unreadCountAllConv = 0;
	$.getJSON(OC.generateUrl('/apps/ocsms/get/new_messages'),
		{ 'lastDate': lastMsgDate },
		function(jsondata, status) {
			var peerListBuf = '';
			var bufferedContacts = [];

			$.each(jsondata['phonelist'], function(id, val) {
				var fn, peerLabel, idxVal;
				idxVal = id.replace(/\//g,' ');
				idxVal2 = idxVal.replace('/ /g','');
				if (typeof jsondata['contacts'][id] == 'undefined') {
					fn = '';
					peerLabel = idxVal;
				}
				else {
					fn = jsondata['contacts'][id];
					peerLabel = fn;
				}

				if (inArray(peerLabel, bufferedContacts)) {
					$("li[peer-label='" + peerLabel + "']").remove();
					peerListBuf = '

' + peerLabel + ' (' + val + ')
';
					$('#app-mailbox-peers ul').prepend(peerListBuf);
					bufferedContacts.push(peerLabel);

					// Re-set conversation because we reload the element
					if (idxVal == curPhoneNumber) {
						changeSelectedConversation($("a[mailbox-navigation='" + idxVal + "']"));
					}

					unreadCountAllConv += parseInt(val);

					// Now bind the events when we click on the phone number
					$("a[mailbox-navigation='" + idxVal + "']").on('click', function (event) {
						var phoneNumber = $(this).attr('mailbox-navigation');
						OC.Util.History.pushState('phonenumber=' + phoneNumber);

						// phoneNumber must exist
						if (phoneNumber != null) {
							fetchConversation(phoneNumber);
							unreadCountAllConv += val;
							changeSelectedConversation($(this));
						}
						event.preventDefault();
					});
				}
			});

			/*
			* Decrement notification step counter, but stop it a zero
			* Stop at zero permit to notify instanly the user when
			* there is new messages in all conversations
			*/

			if (unreadCountNotifStep > 0) {
				unreadCountNotifStep--;
			}

			if (unreadCountAllConv > 0) {
				/*
				* We notify user every two minutes for all messages
				* or if unreadCount changes
				*/
				if (unreadCountNotifStep == 0 || lastUnreadCountAllConv != unreadCountAllConv) {
					desktopNotify(unreadCountAllConv + " unread message(s) for all conversations");
					unreadCountNotifStep = 12;
					lastUnreadCountAllConv = unreadCountAllConv;
				}
			}
		}
	);
};

function setMessageCountInfo(jsondata) {
	if (typeof jsondata['msgCount'] != 'undefined') {
		if (jsondata['msgCount'] == 1) {
			$('#ocsms-phone-msg-nb').html(jsondata['msgCount'] + ' message');
		}
		else {
			$('#ocsms-phone-msg-nb').html(jsondata['msgCount'] + ' messages');
		}
	}
	else {
		$('#ocsms-phone-msg-nb').html('');
	}
}

function fetchConversation(phoneNumber) {
	$.getJSON(OC.generateUrl('/apps/ocsms/get/conversation'),
		{
			'phoneNumber': phoneNumber
		},
		function(jsondata, status) {
			var phoneNumberLabel = phoneNumber;

			if (typeof jsondata['phoneNumbers'] != 'undefined') {
				phoneNumberList = arrayUnique(jsondata['phoneNumbers']);
				phoneNumberLabel = phoneNumberList.toString();
			}

			conversationBuf = formatConversation(jsondata)[1];
			conversationBuf += '

';
			if (typeof jsondata['contactName'] == 'undefined' || jsondata['contactName'] == '') {
				$('#ocsms-phone-label').html(phoneNumberLabel);
				curContactName = phoneNumberLabel;
				$('#ocsms-phone-opt-number').html('');
			}
			else {
				$('#ocsms-phone-label').html(jsondata['contactName']);
				curContactName = jsondata['contactName'];
				$('#ocsms-phone-opt-number').html(phoneNumberLabel);
			}

			setMessageCountInfo(jsondata);

			if ($('#app-content-header').is(':hidden')) {
				$('#app-content-header').show();
			}

			$('#app-content-wrapper').html(conversationBuf);
			$('#app-content').scrollTop(1E10);

			curPhoneNumber = phoneNumber;
		}
	);
}

// Return (int) msgCount, (str) htmlConversation
function formatConversation(jsondata) {
	// Improve jQuery performance
	var buf = "";
	// Improve JS performance
	var msgClass = '';

	var msgCount = 0;
	var formatedDate = '';
	var formatedHour = '00';
	var formatedMin = '00';
	var months = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sep.',
		'Oct.', 'Nov.', 'Dec.'];

	$.each(jsondata["conversation"], function(id, vals) {
		if (vals["type"] == 1) {
			msgClass = "msg-recv";
		}
		else if (vals["type"] == 2) {
			msgClass = "msg-sent";
		}
		else {
			msgClass = '';
		}

		// Store the greater msg date for refresher
		// Note: we divide by 100 because number compare too large integers
		if ((id/100) > (lastMsgDate/100)) {
			lastMsgDate = id;
		}

		// Multiplicate ID to permit date to use it properly
		msgDate = new Date(id*1);

		formatedHour = msgDate.getHours();
		if (formatedHour < 10) {
			formatedHour = '0' + formatedHour;
		}

		formatedMin = msgDate.getMinutes();
		if (formatedMin < 10) {
			formatedMin = '0' + formatedMin;
		}
		formatedDate = msgDate.getDate() + " " + months[msgDate.getMonth()] + " " +
			formatedHour + ":" + formatedMin;

		buf += '

' +
			vals["msg"] + '

' +
			formatedDate + '

';
		msgCount++;

	});

	return [msgCount,buf];
}

function changeSelectedConversation(item) {
	if (item === 'undefined' || item == null) {
		return;
	}

	if (selectedConversation != null) {
		selectedConversation.parent().removeClass('selected');
	}
	selectedConversation = item;
	selectedConversation.parent().addClass('selected');
	selectedConversation.css("font-weight", "normal");
	selectedConversation.html(selectedConversation.attr("mailbox-label"));
}

function fetchInitialPeerList(jsondata) {
	// Use a buffer for better jQuery performance
	var peerListBuf = "";

	var bufferedContacts = [];

	var aScope = angular.element('[ng-controller="OcSmsController"]').scope();

	$.each(jsondata['phonelist'], function(id, val) {
		var fn, peerLabel, idxVal;
		idxVal = id.replace(/\//g,' ');
		idxVal2 = idxVal.replace('/ /g','');
		if (typeof jsondata['contacts'][id] == 'undefined') {
			fn = '';
			peerLabel = idxVal;
		}
		else {
			fn = jsondata['contacts'][id];
			peerLabel = fn;
		}
		if (inArray(peerLabel, bufferedContacts)) {
			aScope.addContact({'label': peerLabel, 'nav': idxVal2, 'avatar': jsondata['photos'][peerLabel]});
			bufferedContacts.push(peerLabel);
		}
	});

	lastMsgDate = jsondata["lastRead"];
}

function initDesktopNotifies() {
	if (!("Notification" in window)) {
		return;
	}

	Notification.requestPermission(function (permission) {
		if(!('permission' in Notification)) {
			Notification.permission = permission;
		}
	});
}

function desktopNotify(msg) {
	if (!("Notification" in window)) {
		return;
	}
	else if (Notification.permission === "granted") {
		new Notification("ownCloud SMS - " + msg);
	}
	else if (Notification.permission !== 'denied') {
		Notification.requestPermission(function (permission) {
			if(!('permission' in Notification)) {
				Notification.permission = permission;
			}
			if (permission === "granted") {
				new Notification("ownCloud SMS - " + msg);
			}
		});
	}
}

function fetchInitialSettings() {
	$.getJSON(OC.generateUrl('/apps/ocsms/get/country'), function(jsondata, status) {
		if (jsondata['status'] == true) {
			$('#sel_intl_phone').val(jsondata["country"]);
		}
		else {
		}
	});
}
(function ($, OC) {
	$(document).ready(function () {
		// Register real title
		originalTitle = document.title;

		// Now bind the events when we click on the phone number
		$.getJSON(OC.generateUrl('/apps/ocsms/get/peerlist'), function(jsondata, status) {
			fetchInitialPeerList(jsondata);

			var pnParam = $.urlParam('phonenumber');
			if (pnParam != null) {
				var urlPhoneNumber = decodeURIComponent(pnParam);
				if (urlPhoneNumber != null) {
					fetchConversation(urlPhoneNumber);
					changeSelectedConversation($("a[mailbox-navigation='" + urlPhoneNumber + "']"));
				}
			}
			// Don't show message headers if no conversation selected
			else {
				if ($('#app-content-header').is(':visible')) {
					$('#app-content-header').hide();
				}
			}

		});
		fetchInitialSettings();
		initDesktopNotifies();
		setInterval(refreshConversation, 10000);
		setInterval(checkNewMessages, 10000);
	});

	// reset count and title
	window.onfocus = function () {
		unreadCountCurrentConv = 0;
		document.title = originalTitle;
	};
})(jQuery, OC);
<commit_msg>Fix conditions...<commit_after>/**
 * ownCloud - ocsms
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Loic Blot <loic.blot@unix-experience.fr>
 * @copyright Loic Blot 2014-2015
 */

// Some global vars to improve performances
var selectedConversation = null;
var curPhoneNumber = null;
var curContactName = '';
var lastMsgDate = 0;
var unreadCountCurrentConv = 0;
var unreadCountAllConv = 0;
var unreadCountNotifStep = 12;
var lastUnreadCountAllConv = 0;
var originalTitle = document.title;

var app = angular.module('OcSms', []);

function inArray(val, arr) {
	return ($.inArray(val, arr) != -1);
}

function arrayUnique(arr) {
	unq = arr.filter(function(item, i, arr) {
		return i == arr.indexOf(item);
	})
	return unq;
}

app.controller('OcSmsController', ['$scope',
	function ($scope) {
		$scope.buttons = [
			{text: "Send"}
		];
		$scope.contacts = [];
		$scope.sendCountry = function () {
			$.post(OC.generateUrl('/apps/ocsms/set/country'),{'country': $('select[name=intl_phone]').val()});
		};
		$scope.loadConversation = function (contact) {
			OC.Util.History.pushState('phonenumber=' + contact.nav);

			// phoneNumber must exist
			if (contact.nav !== null) {
				fetchConversation(contact.nav);
				changeSelectedConversation($("a[mailbox-navigation='" + contact.nav + "']"));
			}
		};

		$scope.addContact = function (ct) {
			$scope.$apply(function () {
				$scope.contacts.push(ct);
			});
		};
	}
]);

$.urlParam = function(name){
	var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
	if (results == null) {
		return null;
	}
	else {
		return results[1] || 0;
	}
};

var refreshConversation = function() {
	// if no conversation selected, then don't fetch page
	if (curPhoneNumber == null) {
		if ($('#app-content-header').is(':visible')) {
			$('#app-content-header').hide();
		}
		return;
	}
	$.getJSON(OC.generateUrl('/apps/ocsms/get/conversation'),
		{
			'phoneNumber': curPhoneNumber,
			"lastDate": lastMsgDate
		},
		function(jsondata, status) {
			var fmt = formatConversation(jsondata);
			conversationBuf = fmt[1];
			if (conversationBuf != '') {
				$('.msg-endtag').before(conversationBuf);
				$('#app-content').scrollTop(1E10);
				// This will blink the tab because there is new messages
				if (document.hasFocus() == false) {
					unreadCountCurrentConv += fmt[0];
					document.title = originalTitle + " (" + unreadCountCurrentConv + ")";
					desktopNotify(unreadCountCurrentConv + " unread message(s) in conversation with " + curContactName);
				}
			}

			setMessageCountInfo(jsondata);

			if ($('#app-content-header').is(':hidden')) {
				$('#app-content-header').show();
			}
		}
	);
};

var checkNewMessages = function() {
	unreadCountAllConv = 0;
	$.getJSON(OC.generateUrl('/apps/ocsms/get/new_messages'),
		{ 'lastDate': lastMsgDate },
		function(jsondata, status) {
			var peerListBuf = '';
			var bufferedContacts = [];

			$.each(jsondata['phonelist'], function(id, val) {
				var fn, peerLabel, idxVal;
				idxVal = id.replace(/\//g,' ');
				idxVal2 = idxVal.replace('/ /g','');
				if (typeof jsondata['contacts'][id] == 'undefined') {
					fn = '';
					peerLabel = idxVal;
				}
				else {
					fn = jsondata['contacts'][id];
					peerLabel = fn;
				}

				if (!inArray(peerLabel, bufferedContacts)) {
					$("li[peer-label='" + peerLabel + "']").remove();
					peerListBuf = '

' + peerLabel + ' (' + val + ')
';

					$('#app-mailbox-peers ul').prepend(peerListBuf);
					bufferedContacts.push(peerLabel);

					// Re-set conversation because we reload the element
					if (idxVal == curPhoneNumber) {
						changeSelectedConversation($("a[mailbox-navigation='" + idxVal + "']"));
					}

					unreadCountAllConv += parseInt(val);

					// Now bind the events when we click on the phone number
					$("a[mailbox-navigation='" + idxVal + "']").on('click', function (event) {
						var phoneNumber = $(this).attr('mailbox-navigation');
						OC.Util.History.pushState('phonenumber=' + phoneNumber);

						// phoneNumber must exist
						if (phoneNumber != null) {
							fetchConversation(phoneNumber);
							unreadCountAllConv += val;
							changeSelectedConversation($(this));
						}
						event.preventDefault();
					});
				}
			});

			/*
			* Decrement notification step counter, but stop it a zero
			* Stop at zero permit to notify instanly the user when
			* there is new messages in all conversations
			*/

			if (unreadCountNotifStep > 0) {
				unreadCountNotifStep--;
			}

			if (unreadCountAllConv > 0) {
				/*
				* We notify user every two minutes for all messages
				* or if unreadCount changes
				*/
				if (unreadCountNotifStep == 0 || lastUnreadCountAllConv != unreadCountAllConv) {
					desktopNotify(unreadCountAllConv + " unread message(s) for all conversations");
					unreadCountNotifStep = 12;
					lastUnreadCountAllConv = unreadCountAllConv;
				}
			}
		}
	);
};

function setMessageCountInfo(jsondata) {
	if (typeof jsondata['msgCount'] != 'undefined') {
		if (jsondata['msgCount'] == 1) {
			$('#ocsms-phone-msg-nb').html(jsondata['msgCount'] + ' message');
		}
		else {
			$('#ocsms-phone-msg-nb').html(jsondata['msgCount'] + ' messages');
		}
	}
	else {
		$('#ocsms-phone-msg-nb').html('');
	}
}

function fetchConversation(phoneNumber) {
	$.getJSON(OC.generateUrl('/apps/ocsms/get/conversation'),
		{
			'phoneNumber': phoneNumber
		},
		function(jsondata, status) {
			var phoneNumberLabel = phoneNumber;

			if (typeof jsondata['phoneNumbers'] != 'undefined') {
				phoneNumberList = arrayUnique(jsondata['phoneNumbers']);
				phoneNumberLabel = phoneNumberList.toString();
			}

			conversationBuf = formatConversation(jsondata)[1];
			conversationBuf += '

';
			if (typeof jsondata['contactName'] == 'undefined' || jsondata['contactName'] == '') {
				$('#ocsms-phone-label').html(phoneNumberLabel);
				curContactName = phoneNumberLabel;
				$('#ocsms-phone-opt-number').html('');
			}
			else {
				$('#ocsms-phone-label').html(jsondata['contactName']);
				curContactName = jsondata['contactName'];
				$('#ocsms-phone-opt-number').html(phoneNumberLabel);
			}

			setMessageCountInfo(jsondata);

			if ($('#app-content-header').is(':hidden')) {
				$('#app-content-header').show();
			}

			$('#app-content-wrapper').html(conversationBuf);
			$('#app-content').scrollTop(1E10);

			curPhoneNumber = phoneNumber;
		}
	);
}

// Return (int) msgCount, (str) htmlConversation
function formatConversation(jsondata) {
	// Improve jQuery performance
	var buf = "";
	// Improve JS performance
	var msgClass = '';

	var msgCount = 0;
	var formatedDate = '';
	var formatedHour = '00';
	var formatedMin = '00';
	var months = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sep.',
		'Oct.', 'Nov.', 'Dec.'];

	$.each(jsondata["conversation"], function(id, vals) {
		if (vals["type"] == 1) {
			msgClass = "msg-recv";
		}
		else if (vals["type"] == 2) {
			msgClass = "msg-sent";
		}
		else {
			msgClass = '';
		}

		// Store the greater msg date for refresher
		// Note: we divide by 100 because number compare too large integers
		if ((id/100) > (lastMsgDate/100)) {
			lastMsgDate = id;
		}

		// Multiplicate ID to permit date to use it properly
		msgDate = new Date(id*1);

		formatedHour = msgDate.getHours();
		if (formatedHour < 10) {
			formatedHour = '0' + formatedHour;
		}

		formatedMin = msgDate.getMinutes();
		if (formatedMin < 10) {
			formatedMin = '0' + formatedMin;
		}
		formatedDate = msgDate.getDate() + " " + months[msgDate.getMonth()] + " " +
			formatedHour + ":" + formatedMin;

		buf += '

' +
			vals["msg"] + '

' +
			formatedDate + '

';
		msgCount++;

	});

	return [msgCount,buf];
}

function changeSelectedConversation(item) {
	if (item === 'undefined' || item == null) {
		return;
	}

	if (selectedConversation != null) {
		selectedConversation.parent().removeClass('selected');
	}
	selectedConversation = item;
	selectedConversation.parent().addClass('selected');
	selectedConversation.css("font-weight", "normal");
	selectedConversation.html(selectedConversation.attr("mailbox-label"));
}

function fetchInitialPeerList(jsondata) {
	// Use a buffer for better jQuery performance
	var peerListBuf = "";

	var bufferedContacts = [];

	var aScope = angular.element('[ng-controller="OcSmsController"]').scope();

	$.each(jsondata['phonelist'], function(id, val) {
		var fn, peerLabel, idxVal;
		idxVal = id.replace(/\//g,' ');
		idxVal2 = idxVal.replace('/ /g','');
		if (typeof jsondata['contacts'][id] == 'undefined') {
			fn = '';
			peerLabel = idxVal;
		}
		else {
			fn = jsondata['contacts'][id];
			peerLabel = fn;
		}
		if (!inArray(peerLabel, bufferedContacts)) {
			aScope.addContact({'label': peerLabel, 'nav': idxVal2, 'avatar': jsondata['photos'][peerLabel]});
			bufferedContacts.push(peerLabel);
		}
	});

	lastMsgDate = jsondata["lastRead"];
}

function initDesktopNotifies() {
	if (!("Notification" in window)) {
		return;
	}

	Notification.requestPermission(function (permission) {
		if(!('permission' in Notification)) {
			Notification.permission = permission;
		}
	});
}

function desktopNotify(msg) {
	if (!("Notification" in window)) {
		return;
	}
	else if (Notification.permission === "granted") {
		new Notification("ownCloud SMS - " + msg);
	}
	else if (Notification.permission !== 'denied') {
		Notification.requestPermission(function (permission) {
			if(!('permission' in Notification)) {
				Notification.permission = permission;
			}
			if (permission === "granted") {
				new Notification("ownCloud SMS - " + msg);
			}
		});
	}
}

function fetchInitialSettings() {
	$.getJSON(OC.generateUrl('/apps/ocsms/get/country'), function(jsondata, status) {
		if (jsondata['status'] == true) {
			$('#sel_intl_phone').val(jsondata["country"]);
		}
		else {
		}
	});
}
(function ($, OC) {
	$(document).ready(function () {
		// Register real title
		originalTitle = document.title;

		// Now bind the events when we click on the phone number
		$.getJSON(OC.generateUrl('/apps/ocsms/get/peerlist'), function(jsondata, status) {
			fetchInitialPeerList(jsondata);

			var pnParam = $.urlParam('phonenumber');
			if (pnParam != null) {
				var urlPhoneNumber = decodeURIComponent(pnParam);
				if (urlPhoneNumber != null) {
					fetchConversation(urlPhoneNumber);
					changeSelectedConversation($("a[mailbox-navigation='" + urlPhoneNumber + "']"));
				}
			}
			// Don't show message headers if no conversation selected
			else {
				if ($('#app-content-header').is(':visible')) {
					$('#app-content-header').hide();
				}
			}

		});
		fetchInitialSettings();
		initDesktopNotifies();
		setInterval(refreshConversation, 10000);
		setInterval(checkNewMessages, 10000);
	});

	// reset count and title
	window.onfocus = function () {
		unreadCountCurrentConv = 0;
		document.title = originalTitle;
	};
})(jQuery, OC);
<|endoftext|>


<commit_before>(function(window, document, _, d3) {
  // Create a namespace for our app
  var openelex = {};
  window.openelex = openelex;

  var stateStatuses = {};
  var geo;
  var svg;
  var path;
  var color;
  var sidebar;

  var defaults = {
    width: 600,
    height: 400,
    mapContainer: '#map',
    sidebarEl: '#sidebar',
    statusJSON: 'data/state_status.json'
  };

  var renderMap = openelex.renderMap = function(options) {
    opts = _.defaults({}, options, defaults);

    //Define map projection

    var projection = d3.geo.albersUsa()
      .translate([opts.width / 2, opts.height / 2])
      .scale([800]);

    //Define path generator
    path = d3.geo.path()
      .projection(projection);

    //Define quantize scale to sort data values into buckets of color
    color = d3.scale.ordinal()
      .range(["rgb(237,248,233)","rgb(116,196,118)","rgb(0,109,44)"])
      //Colors taken from colorbrewer.js, included in the D3 download
      //Set input domain for color scale
      .domain(["not started","partial", "up-to-date"]);

    //Create SVG element
    var mapdiv = d3.select(opts.mapContainer);

    svg = mapdiv.append("svg")
      .attr("width", opts.width)
      .attr("height", opts.height);

    sidebar = d3.select(opts.sidebarEl);

    //var left = d3.select("#main");
    //var sidebar = left.append('div').attr("class","col-md-4 column");

    d3.json(opts.statusJSON, processJSON);
  };

  function processJSON(data) {
    _.each(data, function(state) {
      stateStatuses[state.name] = state;

    });
    loadGeo();
  }

  function loadGeo() {
    //Load in GeoJSON data
    d3.json("data/us-states.json", function(json) {
      json.features.forEach(function(feature) {
        if (stateStatuses[feature.properties.name]) {
          feature.properties = stateStatuses[feature.properties.name];
        } else {
          console.log("No match", feature.properties.name);
        }
      });

      geo = json;
      render();
    });
  }

  function render() {
    var tpl = _.template("<%= state %>
 Metadata Status: <%= status %>
 Volunteer(s): <%= volunteers %>");

    // Bind data and create one path per GeoJSON feature
    svg.selectAll("path")
      .data(geo.features)
      .enter()
      .append("path")
      .attr("d", path)
      .style("fill", function(d) {
        var value = d.properties.metadata_status;
        return value ? color(value) : '#ccc';
      })
      .attr("stroke", "white")
      .attr("stroke-width", 1)
      .on('mouseover', function(d) {
        var dd = d.properties;
        // Extract volunteer names
        var volunteers = _.map(dd.volunteers, function(v) {
          return v.full_name;
        });
        console.debug(volunteers);
        sidebar.html(tpl({
          state: dd.name,
          status: dd.metadata_status,
          volunteers: volunteers.join(', ')
        }));
        sidebar.attr("class", "infobox col-md-4");
      })
      .on('mouseout', function(d) {
        var dd = d.properties;
        sidebar.html(' ');
        sidebar.attr("class", "col-md-4");
      });
  }
})(window, document, _, d3);
<commit_msg>Responsive map.<commit_after>(function(window, document, _, d3) {
  // Create a namespace for our app
  var openelex = {};
  window.openelex = openelex;

  var stateStatuses = {};
  var geo;
  var svg;
  var path;
  var color;
  var sidebar;

  var defaults = {
    mapContainer: '#map',
    sidebarEl: '#sidebar',
    statusJSON: 'data/state_status.json'
  };

  var renderMap = openelex.renderMap = function(options) {
    opts = _.defaults({}, options, defaults);

    var mapdiv = d3.select(opts.mapContainer);
    var aspect = 0.6;
    if (!opts.width) {
      opts.width = mapdiv.node().offsetWidth;
      console.log(opts.width);
    }
    if (!opts.height) {
      opts.height = aspect * opts.width;
    }

    //Define map projection

    var projection = d3.geo.albersUsa()
      .translate([opts.width / 2, opts.height / 2])
      .scale(getScale(opts.width));

    //Define path generator
    path = d3.geo.path()
      .projection(projection);

    //Define quantize scale to sort data values into buckets of color
    color = d3.scale.ordinal()
      .range(["rgb(237,248,233)","rgb(116,196,118)","rgb(0,109,44)"])
      //Colors taken from colorbrewer.js, included in the D3 download
      //Set input domain for color scale
      .domain(["not started","partial", "up-to-date"]);

    // Create SVG element
    svg = mapdiv.append("svg")
      .attr("width", opts.width)
      .attr("height", opts.height);

    sidebar = d3.select(opts.sidebarEl);

    d3.json(opts.statusJSON, processJSON);

    d3.select(window).on('resize', function() {
      var width = mapdiv.node().offsetWidth;
      var height = width * aspect;
      projection.translate([width / 2, height / 2])
        .scale(getScale(width));
      svg.attr("width", width)
        .attr("height", height);
      svg.selectAll('path').attr('d', path);
    });
  };

  /**
   * Returns the scale for the map's projection based on its width.
   */
  function getScale(width) {
    return (width / 800) * 1000;
  }

  function processJSON(data) {
    _.each(data, function(state) {
      stateStatuses[state.name] = state;

    });
    loadGeo();
  }

  function loadGeo() {
    //Load in GeoJSON data
    d3.json("data/us-states.json", function(json) {
      json.features.forEach(function(feature) {
        if (stateStatuses[feature.properties.name]) {
          feature.properties = stateStatuses[feature.properties.name];
        } else {
          console.log("No match", feature.properties.name);
        }
      });

      geo = json;
      render();
    });
  }

  function render() {
    var tpl = _.template("<%= state %>
 Metadata Status: <%= status %>
 Volunteer(s): <%= volunteers %>");

    // Bind data and create one path per GeoJSON feature
    svg.selectAll("path")
      .data(geo.features)
      .enter()
      .append("path")
      .attr("d", path)
      .style("fill", function(d) {
        var value = d.properties.metadata_status;
        return value ? color(value) : '#ccc';
      })
      .attr("stroke", "white")
      .attr("stroke-width", 1)
      .on('mouseover', function(d) {
        var dd = d.properties;
        // Extract volunteer names
        var volunteers = _.map(dd.volunteers, function(v) {
          return v.full_name;
        });
        sidebar.html(tpl({
          state: dd.name,
          status: dd.metadata_status,
          volunteers: volunteers.join(', ')
        }));
        sidebar.attr("class", "infobox col-md-4");
      })
      .on('mouseout', function(d) {
        var dd = d.properties;
        sidebar.html(' ');
        sidebar.attr("class", "col-md-4");
      });
  }
})(window, document, _, d3);
<|endoftext|>


<commit_before>const { createStore, applyMiddleware, compose} = require('redux');
const reducers = require('../reducers');

import {persistStore, autoRehydrate} from 'redux-persist'
import localForage from 'localforage'
import PouchMiddleware from 'pouch-redux-middleware'
import PouchDB from 'pouchdb';
import PouchDBAuthentication from 'pouchdb-authentication';
PouchDB.plugin(PouchDBAuthentication);
import updateSyncStateAction from '../actions/updateSyncState.js'

import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

function getURLParameter(name) {
  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || undefined;
}

module.exports = function(initialState) {

  const db = new PouchDB('slides');

  const pouchMiddleware = PouchMiddleware({
    path: '/slides',
    db,
    actions: {
      remove: doc => store.dispatch({type: 'DELETE_SLIDE', id: doc._id}),
      insert: doc => store.dispatch({type: 'INSERT_SLIDE', slide: doc}),
      update: doc => store.dispatch({type: 'UPDATE_SLIDE', slide: doc})
    }
  })

  const finalCreateStore = compose(
    applyMiddleware(pouchMiddleware),
    autoRehydrate(),
    window.devToolsExtension ? window.devToolsExtension() : f => f
  )(createStore);

  const store = finalCreateStore(reducers, initialState);

  const persistStoreConfig = {
    whitelist: ['settings'],
    storage: localForage
  }
  persistStore(store, persistStoreConfig,() => {
    const remoteDbSettingsFromStore = store.getState().settings;

    const remoteDbSettingsFromUrl = {
      remoteDbUrl: getURLParameter('remoteDbUrl'),
      remoteDbUser: parseInt(getURLParameter('remoteDbUser')),
      remoteDbPassowrd: parseInt(getURLParameter('remoteDbPassword')),
      syncMode: parseInt(getURLParameter('syncMode')),
      enabled: true
    }

    let remoteDbSettings = remoteDbSettingsFromStore;

    // Checking if there are url parameters in order to override the remote database settings from the store
    // Note: Only url and syncMode need to be set, as user and password are optional and only be used with remote
    // databases with restricted access
    if (typeof remoteDbSettingsFromUrl.remoteDbUrl !== 'undefined' &&
        typeof remoteDbSettingsFromUrl.syncMode !== 'undefined' ) {
      remoteDbSettings = remoteDbSettingsFromUrl;
    }

    if (remoteDbSettings.enabled) {
      const remoteDb = new PouchDB(remoteDbSettings.remoteDbUrl, {skipSetup: true});
      // Clearing a previously created session
      remoteDb.logout();

      //var db = new PouchDB('http://localhost:5984/mydb', {skipSetup: true});
      // Trying to authenticate against the remote database if necessary
      if (typeof remoteDbSettings.remoteDbUser !== 'undefined' &&
        typeof remoteDbSettings.remoteDbPassword !== 'undefined' ) {
        remoteDb.login(remoteDbSettings.remoteDbUser, remoteDbSettings.remoteDbPassword, function (err, response) {
          if (err) {
            if (err.name === 'unauthorized') {
              // name or password incorrect
            } else {
              // cosmic rays, a meteor, etc.
            }
          }
        });
      }

      switch (remoteDbSettings.syncMode) {
        case 1:
          db.replicate.from(remoteDb, {
            live: true,
            retry: true
          })
            .on('change', function (change) {
            console.log('yo, something changed!');
          }).on('paused', function (info) {
            console.log('replication was paused, usually because of a lost connection');
          }).on('active', function (info) {
            console.log('replication was resumed');
          }).on('error', function (err) {
            console.log('totally unhandled error (shouldn\'t happen)');
          });
          break;
        case 2:
          db.replicate.to(remoteDb, {
            live: true,
            retry: true
          })
            .on('change', function (change) {
            console.log('yo, something changed!');
          }).on('paused', function (info) {
            console.log('replication was paused, usually because of a lost connection');
          }).on('active', function (info) {
            console.log('replication was resumed');
          }).on('error', function (err) {
            console.log('totally unhandled error (shouldn\'t happen)');
          });
          break;
        case 3:
          db.sync(remoteDb, {
            live: true,
            retry: true
          })
          .on('change', function () {
            store.dispatch(updateSyncStateAction('CHANGE'));
            console.log('yo, something changed!');
          }).on('paused', function () {
            store.dispatch(updateSyncStateAction('PAUSED'));
            console.log('replication was paused, usually because of a lost connection');
          }).on('active', function () {
            store.dispatch(updateSyncStateAction('ACTIVE'));
            console.log('replication was resumed');
          }).on('error', function () {
            store.dispatch(updateSyncStateAction('ERROR'));
            console.log('totally unhandled error (shouldn\'t happen)');
          });
          break;
      }
    }
  });

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextReducer = require('../reducers');
      store.replaceReducer(nextReducer)
    })
  }

  return store
}
<commit_msg>Fixes an unnecessay session teardown<commit_after>const { createStore, applyMiddleware, compose} = require('redux');
const reducers = require('../reducers');

import {persistStore, autoRehydrate} from 'redux-persist'
import localForage from 'localforage'
import PouchMiddleware from 'pouch-redux-middleware'
import PouchDB from 'pouchdb';
import PouchDBAuthentication from 'pouchdb-authentication';
PouchDB.plugin(PouchDBAuthentication);
import updateSyncStateAction from '../actions/updateSyncState.js'

import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

function getURLParameter(name) {
  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || undefined;
}

module.exports = function(initialState) {

  const db = new PouchDB('slides');

  const pouchMiddleware = PouchMiddleware({
    path: '/slides',
    db,
    actions: {
      remove: doc => store.dispatch({type: 'DELETE_SLIDE', id: doc._id}),
      insert: doc => store.dispatch({type: 'INSERT_SLIDE', slide: doc}),
      update: doc => store.dispatch({type: 'UPDATE_SLIDE', slide: doc})
    }
  })

  const finalCreateStore = compose(
    applyMiddleware(pouchMiddleware),
    autoRehydrate(),
    window.devToolsExtension ? window.devToolsExtension() : f => f
  )(createStore);

  const store = finalCreateStore(reducers, initialState);

  const persistStoreConfig = {
    whitelist: ['settings'],
    storage: localForage
  }
  persistStore(store, persistStoreConfig,() => {
    const remoteDbSettingsFromStore = store.getState().settings;

    const remoteDbSettingsFromUrl = {
      remoteDbUrl: getURLParameter('remoteDbUrl'),
      remoteDbUser: parseInt(getURLParameter('remoteDbUser')),
      remoteDbPassowrd: parseInt(getURLParameter('remoteDbPassword')),
      syncMode: parseInt(getURLParameter('syncMode')),
      enabled: true
    }

    let remoteDbSettings = remoteDbSettingsFromStore;

    // Checking if there are url parameters in order to override the remote database settings from the store
    // Note: Only url and syncMode need to be set, as user and password are optional and only be used with remote
    // databases with restricted access
    if (typeof remoteDbSettingsFromUrl.remoteDbUrl !== 'undefined' &&
        typeof remoteDbSettingsFromUrl.syncMode !== 'undefined' ) {
      remoteDbSettings = remoteDbSettingsFromUrl;
    }

    if (remoteDbSettings.enabled) {
      const remoteDb = new PouchDB(remoteDbSettings.remoteDbUrl, {skipSetup: true});

      //var db = new PouchDB('http://localhost:5984/mydb', {skipSetup: true});
      // Trying to authenticate against the remote database if necessary
      if (typeof remoteDbSettings.remoteDbUser !== 'undefined' &&
        typeof remoteDbSettings.remoteDbPassword !== 'undefined' ) {

        // Clearing a previously created session
        remoteDb.logout();

        remoteDb.login(remoteDbSettings.remoteDbUser, remoteDbSettings.remoteDbPassword, function (err, response) {
          if (err) {
            if (err.name === 'unauthorized') {
              // name or password incorrect
            } else {
              // cosmic rays, a meteor, etc.
            }
          }
        });
      }

      switch (remoteDbSettings.syncMode) {
        case 1:
          db.replicate.from(remoteDb, {
            live: true,
            retry: true
          })
            .on('change', function (change) {
            console.log('yo, something changed!');
          }).on('paused', function (info) {
            console.log('replication was paused, usually because of a lost connection');
          }).on('active', function (info) {
            console.log('replication was resumed');
          }).on('error', function (err) {
            console.log('totally unhandled error (shouldn\'t happen)');
          });
          break;
        case 2:
          db.replicate.to(remoteDb, {
            live: true,
            retry: true
          })
            .on('change', function (change) {
            console.log('yo, something changed!');
          }).on('paused', function (info) {
            console.log('replication was paused, usually because of a lost connection');
          }).on('active', function (info) {
            console.log('replication was resumed');
          }).on('error', function (err) {
            console.log('totally unhandled error (shouldn\'t happen)');
          });
          break;
        case 3:
          db.sync(remoteDb, {
            live: true,
            retry: true
          })
          .on('change', function () {
            store.dispatch(updateSyncStateAction('CHANGE'));
            console.log('yo, something changed!');
          }).on('paused', function () {
            store.dispatch(updateSyncStateAction('PAUSED'));
            console.log('replication was paused, usually because of a lost connection');
          }).on('active', function () {
            store.dispatch(updateSyncStateAction('ACTIVE'));
            console.log('replication was resumed');
          }).on('error', function () {
            store.dispatch(updateSyncStateAction('ERROR'));
            console.log('totally unhandled error (shouldn\'t happen)');
          });
          break;
      }
    }
  });

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextReducer = require('../reducers');
      store.replaceReducer(nextReducer)
    })
  }

  return store
}
<|endoftext|>


<commit_before>/*global window:false*/
import _ from 'lodash';

import {EPSILON, velocityI, velocityJ} from './const';
import {maxIterations} from './config';
import * as print from './print';

export class Simulation {

  constructor(board) {
    this.board = board;
    this.history = [];
  }

  /**
   * Clear history and make it one-element list
   * containing initial particles state.
   */
  initialize() {
    const initialState =
      _.reduce(_.range(this.board.level.width), (accI, i) => {
        return _.reduce(_.range(this.board.level.height), (accJ, j) => {
          // Recognize generating tiles by having 'generation' method
          if (!this.board.tileMatrix[i][j].type.generation) {
            return accJ;
          }
          const emissions =
            this.board.tileMatrix[i][j].type.generation(
              this.board.tileMatrix[i][j].rotation
            );
          _.forEach(emissions, (emission) => {
            accJ.push({i:  i,
                       j:  j,
                       to: emission.to,
                       re: emission.re,
                       im: emission.im});
          });
          return accJ;
        }, accI);
      }, []);
    this.history = [initialState];
  }

  /**
   * Make one propagation step and save it in history.
   * Additionally, return it.
   */
  propagate() {
    const lastState = _.last(this.history);
    const displacedState = this.displace(lastState);
    this.absorb(displacedState);
    const newState = this.interact(displacedState);
    this.history.push(newState);

    // debugging purpose
    window.console.log(print.stateToStr(newState));

    return newState;
  }

  /**
   * Creates a new state basing on input state, with particles
   * moved according to their directions.
   */
  // WARNING: creating may be slower than just modifying i and j
  displace(state) {
    return _.map(state, (entry) => {
      // 'to' value = direction + polarization
      const dir = entry.to[0];
      const newI = entry.i + velocityI[dir];
      const newJ = entry.j + velocityJ[dir];
      return {i:  newI,
              j:  newJ,
              to: entry.to,
              re: entry.re,
              im: entry.im};
    });
  }

 absorb(state) {

    // Calculate all absorption probabilites.
    const bins = _.map(state, (entry) => {

      let a = entry.re*entry.re + entry.im*entry.im;

      // Check if particle is out of bound
      if (
           entry.i < 0 || entry.i >= this.board.level.width
        || entry.j < 0 || entry.j >= this.board.level.height
      ) {
        a = a * 1;
      } else {

        const transitionAmps = this.board.tileMatrix[entry.i][entry.j].transitionAmplitudes[entry.to];
        const transmitted = _.chain(transitionAmps)
        .map((change) => change.re * change.re + change.re * change.re)
        .sum();

        a = (1 - transmitted) * a;

      }

      return {i:           entry.i,
              j:           entry.j,
              to:          entry.to,
              probability: a};

    })
    .filter((entry) =>
      entry.probability > EPSILON
    );

    console.log("absorbed", bins);

  }

  /**
   * Creates a new state basing on input state, applying probability
   * function changes from tiles' interactions.
   */
  interact(state) {
    // Collect all transitions into bins. Each bin will be labeled
    // with position (i, j) and momentum direction.
    const bins = _.reduce(state, (acc, entry) => {
      // Check if particle is out of bound
      if (
           entry.i < 0 || entry.i >= this.board.level.width
        || entry.j < 0 || entry.j >= this.board.level.height
      ) {
        return acc;
      }
      const tile = this.board.tileMatrix[entry.i][entry.j];

      // debugging
      if (tile.type.name !== "vacuum") {
        console.log(tile);
      }

      const transition = tile.transitionAmplitudes;
      _.each(transition[entry.to], (change) => {
        const binKey = [entry.i, entry.j, change.to].join('_');
        // (a + bi)(c + di) = (ac - bd) + i(ad + bc)
        const re = entry.re * change.re - entry.im * change.im;
        const im = entry.re * change.im + entry.im * change.re;
        // Add to bin
        if (_.has(acc, binKey)) {
          acc[binKey].re += re;
          acc[binKey].im += im;
        } else {
          acc[binKey] = {i:  entry.i,
                         j:  entry.j,
                         to: change.to,
                         re: re,
                         im: im};
        }
      });
      return acc;
    }, {});
    // Remove keys; filter out zeroes
    return _.values(bins).filter((entry) =>
      entry.re * entry.re + entry.im * entry.im > EPSILON
    );
  }

  /**
   * Propagate until:
   * - all probabilities go to 0
   * - iteration limit is reached
   */
  propagateToEnd() {
    let stepNo, lastStep;
    for (stepNo = 0; stepNo < maxIterations; ++stepNo) {
      lastStep = this.propagate();
      if (!lastStep.length) {
        break;
      }
    }
  }

}
<commit_msg>feat(simulation) quantum measurement<commit_after>/*global window:false*/
import _ from 'lodash';

import {EPSILON, velocityI, velocityJ} from './const';
import {maxIterations} from './config';
import * as print from './print';

export class Simulation {

  constructor(board) {
    this.board = board;
    this.history = [];
  }

  /**
   * Clear history and make it one-element list
   * containing initial particles state.
   */
  initialize() {
    const initialState =
      _.reduce(_.range(this.board.level.width), (accI, i) => {
        return _.reduce(_.range(this.board.level.height), (accJ, j) => {
          // Recognize generating tiles by having 'generation' method
          if (!this.board.tileMatrix[i][j].type.generation) {
            return accJ;
          }
          const emissions =
            this.board.tileMatrix[i][j].type.generation(
              this.board.tileMatrix[i][j].rotation
            );
          _.forEach(emissions, (emission) => {
            accJ.push({i:  i,
                       j:  j,
                       to: emission.to,
                       re: emission.re,
                       im: emission.im});
          });
          return accJ;
        }, accI);
      }, []);

    // debugging purpose
    window.console.log("Simulation started:");
    window.console.log(print.stateToStr(initialState));

    this.history = [initialState];
  }

  /**
   * Make one propagation step and save it in history.
   * Additionally, return it.
   */
  propagate(quantum = true) {

    const lastState = _.last(this.history);
    const displacedState = this.displace(lastState);
    let absorbed = null;
    if (quantum) {
      absorbed = this.absorb(displacedState);
    }
    let newState = this.interact(displacedState);
    if (quantum) {
      newState = this.normalize(newState);
    }

    this.history.push(newState);

    if (absorbed !== null) {
      window.console.log("absorbed", absorbed);
      return [];
    } else {
      window.console.log(print.stateToStr(newState));
      return newState;
    }

  }

  /**
   * Creates a new state basing on input state, with particles
   * moved according to their directions.
   */
  // WARNING: creating may be slower than just modifying i and j
  displace(state) {
    return _.map(state, (entry) => {
      // 'to' value = direction + polarization
      const dir = entry.to[0];
      const newI = entry.i + velocityI[dir];
      const newJ = entry.j + velocityJ[dir];
      return {i:  newI,
              j:  newJ,
              to: entry.to,
              re: entry.re,
              im: entry.im};
    });
  }

 absorb(state) {

    // Calculate all absorption probabilites.
    const bins = _.map(state, (entry) => {

      let a = entry.re*entry.re + entry.im*entry.im;
      let tile = null;

      // Check if particle is out of bound
      if (
           entry.i < 0 || entry.i >= this.board.level.width
        || entry.j < 0 || entry.j >= this.board.level.height
      ) {
        a = a * 1;
      } else {
        tile = this.board.tileMatrix[entry.i][entry.j];
        const transitionAmps = tile.transitionAmplitudes[entry.to]
        const transmitted = _.chain(transitionAmps)
          .map((change) => change.re * change.re + change.re * change.re)
          .sum();

        a = (1 - transmitted) * a;

      }

      return {i:           entry.i,
              j:           entry.j,
              to:          entry.to,
              tile:        tile,
              probability: a};
    })
    .filter((entry) =>
      entry.probability > EPSILON
    );

    const rand = Math.random();
    let probSum = 0;

    for (let k = 0; k < bins.length; k++) {
      probSum += bins[k].probability;
      if (probSum > rand) {
        return bins[k];
      }
    }

    return null;

  }

  /**
   * Creates a new state basing on input state, applying probability
   * function changes from tiles' interactions.
   */
  interact(state) {
    // Collect all transitions into bins. Each bin will be labeled
    // with position (i, j) and momentum direction.
    const bins = _.reduce(state, (acc, entry) => {
      // Check if particle is out of bound
      if (
           entry.i < 0 || entry.i >= this.board.level.width
        || entry.j < 0 || entry.j >= this.board.level.height
      ) {
        return acc;
      }
      const tile = this.board.tileMatrix[entry.i][entry.j];

      // debugging
      if (tile.type.name !== "vacuum") {
        console.log(tile);
      }

      const transition = tile.transitionAmplitudes;
      _.each(transition[entry.to], (change) => {
        const binKey = [entry.i, entry.j, change.to].join('_');
        // (a + bi)(c + di) = (ac - bd) + i(ad + bc)
        const re = entry.re * change.re - entry.im * change.im;
        const im = entry.re * change.im + entry.im * change.re;
        // Add to bin
        if (_.has(acc, binKey)) {
          acc[binKey].re += re;
          acc[binKey].im += im;
        } else {
          acc[binKey] = {i:  entry.i,
                         j:  entry.j,
                         to: change.to,
                         re: re,
                         im: im};
        }
      });
      return acc;
    }, {});
    // Remove keys; filter out zeroes
    return _.values(bins).filter((entry) =>
      entry.re * entry.re + entry.im * entry.im > EPSILON
    );
  }

  normalize(state) {

    let norm = _.chain(state)
      .map((entry) => entry.re * entry.re + entry.im * entry.im)
      .sum();

    norm = Math.sqrt(norm);

    return state.map((entry) =>
      _.assign(entry, {
        re: entry.re / norm,
        im: entry.im / norm
      })
    );

  }

  /**
   * Propagate until:
   * - all probabilities go to 0
   * - iteration limit is reached
   */
  propagateToEnd() {
    let stepNo, lastStep;
    for (stepNo = 0; stepNo < maxIterations; ++stepNo) {
      lastStep = this.propagate(true);
      if (!lastStep.length) {
        break;
      }
    }
  }

}
<|endoftext|>


<commit_before>var express = require('express');
var apiHandler = require('../../handler/APIHandler');
var apiCaller = require('./apicalls').apiCaller;
var settings = require("../../utils/Settings");

var swaggerModels = {
  'models': {
    'SessionInfo' : {
      "id": 'SessionInfo',
      "properties": {
        "id": {
          "type": "string"
        },
        "authorID": {
          "type": "string"
        },
        "groupID":{
          "type":"string"
        },
        "validUntil":{
          "type":"long"
        }
      }
    },
    'UserInfo' : {
      "id": 'UserInfo',
      "properties": {
        "id": {
          "type": "string"
        },
        "colorId": {
          "type": "string"
        },
        "name":{
          "type":"string"
        },
        "timestamp":{
          "type":"long"
        }
      }
    },
    'Message' : {
      "id": 'Message',
      "properties": {
        "text": {
          "type": "string"
        },
        "userId": {
          "type": "string"
        },
        "userName":{
          "type":"string"
        },
        "time":{
          "type":"long"
        }
      }
    }
  }
};

function sessionListResponseProcessor(res) {
  if (res.data) {
    var sessions = [];
    for (var sessionId in res.data) {
      var sessionInfo = res.data[sessionId];
      sessionId["id"] = sessionId;
      sessions.push(sessionInfo);
    }
    res.data = sessions;
  }

  return res;
}

// We'll add some more info to the API methods
var API = {

  // Group
  "group": {
    "create" : {
      "func" : "createGroup",
      "description": "creates a new group",
      "response": {"groupID":{"type":"string"}}
    },
    "createIfNotExistsFor" : {
      "func": "createGroupIfNotExistsFor",
      "description": "this functions helps you to map your application group ids to Etherpad group ids",
      "response": {"groupID":{"type":"string"}}
    },
    "delete" : {
      "func": "deleteGroup",
      "description": "deletes a group"
    },
    "listPads" : {
      "func": "listPads",
      "description": "returns all pads of this group",
      "response": {"padIDs":{"type":"List", "items":{"type":"string"}}}
    },
    "createPad" : {
      "func": "createGroupPad",
      "description": "creates a new pad in this group"
    },
    "listSessions": {
      "func": "listSessionsOfGroup",
      "responseProcessor": sessionListResponseProcessor,
      "description": "",
      "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}}
    },
   "list": {
      "func": "listAllGroups",
      "description": "",
      "response": {"groupIDs":{"type":"List", "items":{"type":"string"}}}
    },
  },

  // Author
  "author": {
    "create" : {
      "func" : "createAuthor",
      "description": "creates a new author",
      "response": {"authorID":{"type":"string"}}
    },
    "createIfNotExistsFor": {
      "func": "createAuthorIfNotExistsFor",
      "description": "this functions helps you to map your application author ids to Etherpad author ids",
      "response": {"authorID":{"type":"string"}}
    },
    "listPads": {
      "func": "listPadsOfAuthor",
      "description": "returns an array of all pads this author contributed to",
      "response": {"padIDs":{"type":"List", "items":{"type":"string"}}}
    },
    "listSessions": {
      "func": "listSessionsOfAuthor",
      "responseProcessor": sessionListResponseProcessor,
      "description": "returns all sessions of an author",
      "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}}
    },
    // We need an operation that return a UserInfo so it can be picked up by the codegen :(
    "getName" : {
      "func": "getAuthorName",
      "description": "Returns the Author Name of the author",
      "responseProcessor": function(response) {
        if (response.data) {
          response["info"] = {"name": response.data.authorName};
          delete response["data"];
        }
      },
      "response": {"info":{"type":"UserInfo"}}
    }
  },
  "session": {
    "create" : {
      "func": "createSession",
      "description": "creates a new session. validUntil is an unix timestamp in seconds",
      "response": {"sessionID":{"type":"string"}}
    },
    "delete" : {
      "func": "deleteSession",
      "description": "deletes a session"
    },
    // We need an operation that returns a SessionInfo so it can be picked up by the codegen :(
    "info": {
      "func": "getSessionInfo",
      "description": "returns informations about a session",
      "responseProcessor": function(response) {
        // move this to info
        if (response.data) {
          response["info"] = response.data;
          delete response["data"];
        }
      },
      "response": {"info":{"type":"SessionInfo"}}
    }
  },
  "pad": {
    "listAll" : {
      "func": "listAllPads",
      "description": "list all the pads",
      "response": {"padIDs":{"type":"List", "items": {"type" : "string"}}}
    },
    "createDiffHTML" : {
      "func" : "createDiffHTML",
      "description": "",
      "response": {}
    },
    "create" : {
      "func" : "createPad",
      "description": "creates a new (non-group) pad. Note that if you need to create a group Pad, you should call createGroupPad"
    },
    "getText" : {
      "func" : "getText",
      "description": "returns the text of a pad",
      "response": {"text":{"type":"string"}}
    },
    "setText" : {
      "func" : "setText",
      "description": "sets the text of a pad"
    },
    "getHTML": {
      "func" : "getHTML",
      "description": "returns the text of a pad formatted as HTML",
      "response": {"html":{"type":"string"}}
    },
    "setHTML": {
      "func" : "setHTML",
      "description": "sets the text of a pad with HTML"
    },
    "getRevisionsCount": {
      "func" : "getRevisionsCount",
      "description": "returns the number of revisions of this pad",
      "response": {"revisions":{"type":"long"}}
    },
    "getLastEdited": {
      "func" : "getLastEdited",
      "description": "returns the timestamp of the last revision of the pad",
      "response": {"lastEdited":{"type":"long"}}
    },
    "delete": {
      "func" : "deletePad",
      "description": "deletes a pad"
    },
    "getReadOnlyID": {
      "func" : "getReadOnlyID",
      "description": "returns the read only link of a pad",
      "response": {"readOnlyID":{"type":"string"}}
    },
    "setPublicStatus": {
      "func": "setPublicStatus",
      "description": "sets a boolean for the public status of a pad"
    },
    "getPublicStatus": {
      "func": "getPublicStatus",
      "description": "return true of false",
      "response": {"publicStatus":{"type":"boolean"}}
    },
    "setPassword": {
      "func": "setPassword",
      "description": "returns ok or a error message"
    },
    "isPasswordProtected": {
      "func": "isPasswordProtected",
      "description": "returns true or false",
      "response": {"passwordProtection":{"type":"boolean"}}
    },
    "authors": {
      "func": "listAuthorsOfPad",
      "description": "returns an array of authors who contributed to this pad",
      "response": {"authorIDs":{"type":"List", "items":{"type" : "string"}}}
    },
    "usersCount": {
      "func": "padUsersCount",
      "description": "returns the number of user that are currently editing this pad",
      "response": {"padUsersCount":{"type": "long"}}
    },
    "users": {
      "func": "padUsers",
      "description": "returns the list of users that are currently editing this pad",
      "response": {"padUsers":{"type":"List", "items":{"type": "UserInfo"}}}
    },
    "sendClientsMessage": {
      "func": "sendClientsMessage",
      "description": "sends a custom message of type msg to the pad"
    },
    "checkToken" : {
      "func": "checkToken",
      "description": "returns ok when the current api token is valid"
    },
    "getChatHistory": {
      "func": "getChatHistory",
      "description": "returns the chat history",
      "response": {"messages":{"type":"List", "items": {"type" : "Message"}}}
    },
    // We need an operation that returns a Message so it can be picked up by the codegen :(
    "getChatHead": {
      "func": "getChatHead",
      "description": "returns the chatHead (chat-message) of the pad",
      "responseProcessor": function(response) {
        // move this to info
        if (response.data) {
          response["chatHead"] = {"time": response.data["chatHead"]};
          delete response["data"];
        }
      },
      "response": {"chatHead":{"type":"Message"}}
    }
  }
};

function capitalise(string){
  return string.charAt(0).toUpperCase() + string.slice(1);
}

for (var resource in API) {
  for (var func in API[resource]) {

    // The base response model
    var responseModel = {
      "properties": {
        "code":{
          "type":"int"
        },
        "message":{
          "type":"string"
        }
      }
    };

    var responseModelId = "Response";

    // Add the data properties (if any) to the response
    if (API[resource][func]["response"]) {
      // This is a specific response so let's set a new id
      responseModelId = capitalise(resource) + capitalise(func) + "Response";

      for(var prop in API[resource][func]["response"]) {
        var propType = API[resource][func]["response"][prop];
        responseModel["properties"][prop] = propType;
      }
    }

    // Add the id
    responseModel["id"] = responseModelId;

    // Add this to the swagger models
    swaggerModels['models'][responseModelId] = responseModel;

    // Store the response model id
    API[resource][func]["responseClass"] = responseModelId;

  }
}

function newSwagger() {
  var swagger_module = require.resolve("swagger-node-express");
  if (require.cache[swagger_module]) {
    // delete the child modules from cache
    require.cache[swagger_module].children.forEach(function(m)  {delete require.cache[m.id];});
    // delete the module from cache
    delete require.cache[swagger_module];
  }
  return require("swagger-node-express");
}

exports.expressCreateServer = function (hook_name, args, cb) {

  for (var version in apiHandler.version) {

    var swagger = newSwagger();
    var basePath = "/rest/" + version;

    // Let's put this under /rest for now
    var subpath = express();

    args.app.use(basePath, subpath);

    swagger.setAppHandler(subpath);

    swagger.addModels(swaggerModels);

    for (var resource in API) {

      for (var funcName in API[resource]) {
        var func = API[resource][funcName];

        // get the api function
        var apiFunc = apiHandler.version[version][func["func"]];

        // Skip this one if it does not exist in the version
        if(!apiFunc) {
          continue;
        }

        var swaggerFunc = {
          'spec': {
            "description" : func["description"],
            "path" : "/" + resource + "/" + funcName,
            "summary" : funcName,
            "nickname" : funcName,
            "method": "GET",
            "params" : apiFunc.map( function(param) {
              return swagger.queryParam(param, param, "string");
            }),
            "responseClass" : func["responseClass"]
          },
          'action': (function(func, responseProcessor) {
            return function (req,res) {
              req.params.version = version;
              req.params.func = func; // call the api function

              //wrap the send function so we can process the response
              res.__swagger_send = res.send;
              res.send = function (response) {
                // ugly but we need to get this as json
                response = JSON.parse(response);
                // process the response if needed
                if (responseProcessor) {
                  response = responseProcessor(response);
                }
                // Let's move everything out of "data"
                if (response.data) {
                  for(var prop in response.data) {
                    response[prop] = response.data[prop];
                    delete response.data;
                  }
                }
                response = JSON.stringify(response);
                res.__swagger_send(response);
              };

              apiCaller(req, res, req.query);
            };
          })(func["func"], func["responseProcessor"]) // must use a closure here
        };

        swagger.addGet(swaggerFunc);
      }
    }

    swagger.setHeaders = function setHeaders(res) {
      res.header('Access-Control-Allow-Origin', "*");
    };

    swagger.configureSwaggerPaths("", "/api" , "");

    swagger.configure("http://" + settings.ip + ":" + settings.port + basePath, version);
  }
};
<commit_msg>hack to avoid warnings in swagger usage<commit_after>var express = require('express');
var apiHandler = require('../../handler/APIHandler');
var apiCaller = require('./apicalls').apiCaller;
var settings = require("../../utils/Settings");

var swaggerModels = {
  'models': {
    'SessionInfo' : {
      "id": 'SessionInfo',
      "properties": {
        "id": {
          "type": "string"
        },
        "authorID": {
          "type": "string"
        },
        "groupID":{
          "type":"string"
        },
        "validUntil":{
          "type":"long"
        }
      }
    },
    'UserInfo' : {
      "id": 'UserInfo',
      "properties": {
        "id": {
          "type": "string"
        },
        "colorId": {
          "type": "string"
        },
        "name":{
          "type":"string"
        },
        "timestamp":{
          "type":"long"
        }
      }
    },
    'Message' : {
      "id": 'Message',
      "properties": {
        "text": {
          "type": "string"
        },
        "userId": {
          "type": "string"
        },
        "userName":{
          "type":"string"
        },
        "time":{
          "type":"long"
        }
      }
    }
  }
};

function sessionListResponseProcessor(res) {
  if (res.data) {
    var sessions = [];
    for (var sessionId in res.data) {
      var sessionInfo = res.data[sessionId];
      sessionId["id"] = sessionId;
      sessions.push(sessionInfo);
    }
    res.data = sessions;
  }

  return res;
}

// We'll add some more info to the API methods
var API = {

  // Group
  "group": {
    "create" : {
      "func" : "createGroup",
      "description": "creates a new group",
      "response": {"groupID":{"type":"string"}}
    },
    "createIfNotExistsFor" : {
      "func": "createGroupIfNotExistsFor",
      "description": "this functions helps you to map your application group ids to Etherpad group ids",
      "response": {"groupID":{"type":"string"}}
    },
    "delete" : {
      "func": "deleteGroup",
      "description": "deletes a group"
    },
    "listPads" : {
      "func": "listPads",
      "description": "returns all pads of this group",
      "response": {"padIDs":{"type":"List", "items":{"type":"string"}}}
    },
    "createPad" : {
      "func": "createGroupPad",
      "description": "creates a new pad in this group"
    },
    "listSessions": {
      "func": "listSessionsOfGroup",
      "responseProcessor": sessionListResponseProcessor,
      "description": "",
      "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}}
    },
   "list": {
      "func": "listAllGroups",
      "description": "",
      "response": {"groupIDs":{"type":"List", "items":{"type":"string"}}}
    },
  },

  // Author
  "author": {
    "create" : {
      "func" : "createAuthor",
      "description": "creates a new author",
      "response": {"authorID":{"type":"string"}}
    },
    "createIfNotExistsFor": {
      "func": "createAuthorIfNotExistsFor",
      "description": "this functions helps you to map your application author ids to Etherpad author ids",
      "response": {"authorID":{"type":"string"}}
    },
    "listPads": {
      "func": "listPadsOfAuthor",
      "description": "returns an array of all pads this author contributed to",
      "response": {"padIDs":{"type":"List", "items":{"type":"string"}}}
    },
    "listSessions": {
      "func": "listSessionsOfAuthor",
      "responseProcessor": sessionListResponseProcessor,
      "description": "returns all sessions of an author",
      "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}}
    },
    // We need an operation that return a UserInfo so it can be picked up by the codegen :(
    "getName" : {
      "func": "getAuthorName",
      "description": "Returns the Author Name of the author",
      "responseProcessor": function(response) {
        if (response.data) {
          response["info"] = {"name": response.data.authorName};
          delete response["data"];
        }
      },
      "response": {"info":{"type":"UserInfo"}}
    }
  },
  "session": {
    "create" : {
      "func": "createSession",
      "description": "creates a new session. validUntil is an unix timestamp in seconds",
      "response": {"sessionID":{"type":"string"}}
    },
    "delete" : {
      "func": "deleteSession",
      "description": "deletes a session"
    },
    // We need an operation that returns a SessionInfo so it can be picked up by the codegen :(
    "info": {
      "func": "getSessionInfo",
      "description": "returns informations about a session",
      "responseProcessor": function(response) {
        // move this to info
        if (response.data) {
          response["info"] = response.data;
          delete response["data"];
        }
      },
      "response": {"info":{"type":"SessionInfo"}}
    }
  },
  "pad": {
    "listAll" : {
      "func": "listAllPads",
      "description": "list all the pads",
      "response": {"padIDs":{"type":"List", "items": {"type" : "string"}}}
    },
    "createDiffHTML" : {
      "func" : "createDiffHTML",
      "description": "",
      "response": {}
    },
    "create" : {
      "func" : "createPad",
      "description": "creates a new (non-group) pad. Note that if you need to create a group Pad, you should call createGroupPad"
    },
    "getText" : {
      "func" : "getText",
      "description": "returns the text of a pad",
      "response": {"text":{"type":"string"}}
    },
    "setText" : {
      "func" : "setText",
      "description": "sets the text of a pad"
    },
    "getHTML": {
      "func" : "getHTML",
      "description": "returns the text of a pad formatted as HTML",
      "response": {"html":{"type":"string"}}
    },
    "setHTML": {
      "func" : "setHTML",
      "description": "sets the text of a pad with HTML"
    },
    "getRevisionsCount": {
      "func" : "getRevisionsCount",
      "description": "returns the number of revisions of this pad",
      "response": {"revisions":{"type":"long"}}
    },
    "getLastEdited": {
      "func" : "getLastEdited",
      "description": "returns the timestamp of the last revision of the pad",
      "response": {"lastEdited":{"type":"long"}}
    },
    "delete": {
      "func" : "deletePad",
      "description": "deletes a pad"
    },
    "getReadOnlyID": {
      "func" : "getReadOnlyID",
      "description": "returns the read only link of a pad",
      "response": {"readOnlyID":{"type":"string"}}
    },
    "setPublicStatus": {
      "func": "setPublicStatus",
      "description": "sets a boolean for the public status of a pad"
    },
    "getPublicStatus": {
      "func": "getPublicStatus",
      "description": "return true of false",
      "response": {"publicStatus":{"type":"boolean"}}
    },
    "setPassword": {
      "func": "setPassword",
      "description": "returns ok or a error message"
    },
    "isPasswordProtected": {
      "func": "isPasswordProtected",
      "description": "returns true or false",
      "response": {"passwordProtection":{"type":"boolean"}}
    },
    "authors": {
      "func": "listAuthorsOfPad",
      "description": "returns an array of authors who contributed to this pad",
      "response": {"authorIDs":{"type":"List", "items":{"type" : "string"}}}
    },
    "usersCount": {
      "func": "padUsersCount",
      "description": "returns the number of user that are currently editing this pad",
      "response": {"padUsersCount":{"type": "long"}}
    },
    "users": {
      "func": "padUsers",
      "description": "returns the list of users that are currently editing this pad",
      "response": {"padUsers":{"type":"List", "items":{"type": "UserInfo"}}}
    },
    "sendClientsMessage": {
      "func": "sendClientsMessage",
      "description": "sends a custom message of type msg to the pad"
    },
    "checkToken" : {
      "func": "checkToken",
      "description": "returns ok when the current api token is valid"
    },
    "getChatHistory": {
      "func": "getChatHistory",
      "description": "returns the chat history",
      "response": {"messages":{"type":"List", "items": {"type" : "Message"}}}
    },
    // We need an operation that returns a Message so it can be picked up by the codegen :(
    "getChatHead": {
      "func": "getChatHead",
      "description": "returns the chatHead (chat-message) of the pad",
      "responseProcessor": function(response) {
        // move this to info
        if (response.data) {
          response["chatHead"] = {"time": response.data["chatHead"]};
          delete response["data"];
        }
      },
      "response": {"chatHead":{"type":"Message"}}
    }
  }
};

function capitalise(string){
  return string.charAt(0).toUpperCase() + string.slice(1);
}

for (var resource in API) {
  for (var func in API[resource]) {

    // The base response model
    var responseModel = {
      "properties": {
        "code":{
          "type":"int"
        },
        "message":{
          "type":"string"
        }
      }
    };

    var responseModelId = "Response";

    // Add the data properties (if any) to the response
    if (API[resource][func]["response"]) {
      // This is a specific response so let's set a new id
      responseModelId = capitalise(resource) + capitalise(func) + "Response";

      for(var prop in API[resource][func]["response"]) {
        var propType = API[resource][func]["response"][prop];
        responseModel["properties"][prop] = propType;
      }
    }

    // Add the id
    responseModel["id"] = responseModelId;

    // Add this to the swagger models
    swaggerModels['models'][responseModelId] = responseModel;

    // Store the response model id
    API[resource][func]["responseClass"] = responseModelId;

  }
}

function newSwagger() {
  var swagger_module = require.resolve("swagger-node-express");
  if (require.cache[swagger_module]) {
    // delete the child modules from cache
    require.cache[swagger_module].children.forEach(function(m)  {delete require.cache[m.id];});
    // delete the module from cache
    delete require.cache[swagger_module];
  }
  return require("swagger-node-express");
}

exports.expressCreateServer = function (hook_name, args, cb) {

  for (var version in apiHandler.version) {

    var swagger = newSwagger();
    var basePath = "/rest/" + version;

    // Let's put this under /rest for now
    var subpath = express();

    args.app.use(basePath, subpath);

    //hack!
    var swagger_temp = swagger
    swagger = swagger.createNew(subpath);
    swagger.params = swagger_temp.params
    swagger.queryParam = swagger_temp.queryParam
    swagger.pathParam = swagger_temp.pathParam
    swagger.bodyParam = swagger_temp.bodyParam
    swagger.formParam = swagger_temp.formParam
    swagger.headerParam = swagger_temp.headerParam
    swagger.error = swagger_temp.error
    //swagger.setAppHandler(subpath);

    swagger.addModels(swaggerModels);

    for (var resource in API) {

      for (var funcName in API[resource]) {
        var func = API[resource][funcName];

        // get the api function
        var apiFunc = apiHandler.version[version][func["func"]];

        // Skip this one if it does not exist in the version
        if(!apiFunc) {
          continue;
        }

        var swaggerFunc = {
          'spec': {
            "description" : func["description"],
            "path" : "/" + resource + "/" + funcName,
            "summary" : funcName,
            "nickname" : funcName,
            "method": "GET",
            "params" : apiFunc.map( function(param) {
              return swagger.queryParam(param, param, "string");
            }),
            "responseClass" : func["responseClass"]
          },
          'action': (function(func, responseProcessor) {
            return function (req,res) {
              req.params.version = version;
              req.params.func = func; // call the api function

              //wrap the send function so we can process the response
              res.__swagger_send = res.send;
              res.send = function (response) {
                // ugly but we need to get this as json
                response = JSON.parse(response);
                // process the response if needed
                if (responseProcessor) {
                  response = responseProcessor(response);
                }
                // Let's move everything out of "data"
                if (response.data) {
                  for(var prop in response.data) {
                    response[prop] = response.data[prop];
                    delete response.data;
                  }
                }
                response = JSON.stringify(response);
                res.__swagger_send(response);
              };

              apiCaller(req, res, req.query);
            };
          })(func["func"], func["responseProcessor"]) // must use a closure here
        };

        swagger.addGet(swaggerFunc);
      }
    }

    swagger.setHeaders = function setHeaders(res) {
      res.header('Access-Control-Allow-Origin', "*");
    };

    swagger.configureSwaggerPaths("", "/api" , "");

    swagger.configure("http://" + settings.ip + ":" + settings.port + basePath, version);
  }
};
<|endoftext|>