<commit_before>const dgram = require('dgram')
const os = require('os')
const path = require('path')
const fs = require('fs')

const dragDrop = require('drag-drop')
const { remote, app } = require('electron')
const dialog = remote.dialog
const win = remote.getCurrentWindow()

const httpServer = require('./server')
const httpClient = require('https').request

const client = dgram.createSocket('udp4')
const server = dgram.createSocket('udp4')

const PORT = 4321
const MC = '224.0.0.1'

function send (o) {
  const message = Buffer.from(JSON.stringify(o))
  client.send(message, 0, message.length, PORT, MC)
}

//
// Dont accept arbitrary drops
//
dragDrop(document.body, () => {})

//
// Advertise a message
//
setInterval(() => {
  send({
    event: 'join',
    name: os.hostname().replace(/\.local/g, ''),
    platform: os.platform(),
    ctime: Date.now()
  })
}, 1500)

//
// Add a close button
//
const close = document.querySelector('.close')
close.addEventListener('click', () => {
  app.close()
})

const me = document.querySelector('#me')
me.textContent = os.hostname()

//
// Drop your avatar
//
dragDrop(me, (files) => {
  const reader = new window.FileReader()
  reader.onerror = err => {
    console.error(err)
  }
  reader.onload = e => {
    me.style.backgroundImage = 'url("' + e.target.result + '")'
    me.textContent = ''
    // fs.writeFileSync(
  }
  reader.readAsDataURL(files[0])
})

//
// Add our hostname to the `me` icon.
//

httpServer((req, res) => {
  const filename = req.headers['x-filename']

  if (req.url === '/upload') {
    const message = [
      'Do you want to accept the file',
      filename,
      'from',
      req.headers['x-from'] + '?'
    ].join(' ')

    const opts = {
      type: 'question',
      buttons: ['ok', 'cancel'],
      title: 'Confirm',
      message
    }

    const result = dialog.showMessageBox(win, opts)

    if (result === 0) {
      const dest = path.join(remote.app.getPath('downloads'), filename)
      const writeStream = fs.createWriteStream(dest)

      req.pipe(writeStream)
    }
  } else {
    // TODO serve the app so people can download it
  }
})

const registry = {}

function getData (src, cb) {
  const reader = new window.FileReader()
  reader.onerror = err => cb(err)
  reader.onload = e => cb(null, e.target.result)
  reader.readAsArrayBuffer(src)
}

function onFilesDropped (ip, files) {
  files.forEach(file => {
    const opts = {
      host: ip,
      port: 9988,
      path: '/upload',
      method: 'POST',
      rejectUnauthorized: false,
      headers: {
        'Content-Type': file.type,
        'x-filename': file.name,
        'x-from': os.hostname()
      }
    }

    getData(file, (err, data) => {
      if (err) return console.error(err)
      const req = httpClient(opts, res => {
        if (res.statusCode !== 200) {
          res.on('data', data => {
            console.error(res.statusCode, data)
          })
        }
      })

      req.end(Buffer.from(data))
    })
  })
}

//
// Create a tcp server
//

function joined (msg, rinfo) {
  const me = os.hostname().replace(/\.local/g, '')
  msg.name = msg.name.replace(/\.local/g, '')

  //
  // Don't show me my own machine as a peer
  //
  if (!process.env['DEBUG'] && msg.name === me) {
    return
  }

  //
  // If the peer is already rendered, just return
  //
  const selector = `[data-name="${msg.name}"]`
  if (document.querySelector(selector)) return

  //
  // Otherwise, create a peer and add it to the list.
  //
  const peers = document.querySelector('#peers')
  const peer = document.createElement('div')

  peer.className = 'peer adding adding-anim'
  peer.setAttribute('data-name', msg.name)
  peer.setAttribute('data-ip', rinfo.address)
  peer.setAttribute('data-platform', msg.platform)

  const avatar = document.createElement('div')
  avatar.className = 'avatar ' + msg.platform
  peer.appendChild(avatar)

  const name = document.createElement('address')
  name.textContent = msg.name
  name.title = rinfo.address
  peer.appendChild(name)

  peers.appendChild(peer)

  window.requestAnimationFrame(() => requestAnimationFrame(() => peer.classList.remove('adding')));
  peer.addEventListener('transitionend', e => {
    if (e.propertyName !== 'transform') return;
    peer.classList.remove('adding-anim');
  });
  //
  // Add a drag drop event to the peer
  //
  dragDrop(peer, (files) => {
    onFilesDropped(peer.getAttribute('data-ip'), files)
  })

  // remove inital empty message when finding peers
  const selectorEmptyState = document.querySelector('#empty-message')
  if (selectorEmptyState) selectorEmptyState.parentNode.removeChild(selectorEmptyState)
}

function parted (msg) {
  const selector = `.peer[data-name="${msg.name}"]`
  const peer = document.querySelector(selector)
  if (peer) peer.parentNode.removeChild(peer)
}

function cleanUp () {
  for (var key in registry) {
    if (registry[key] && (Date.now() - registry[key].ctime) > 9000) {
      parted(registry[key])
      registry[key] = null
    }
  }
}

server.on('error', (err) => {
  console.error(err)
  server.close()
})

server.on('message', (msg, rinfo) => {
  msg = JSON.parse(msg)
  if (!registry[msg.name] && msg.event === 'join') {
    joined(msg, rinfo)
  }
  registry[msg.name] = msg
})

server.on('listening', () => {
  console.log(`Listening on ${PORT}`)
})

server.bind(PORT)

setInterval(cleanUp, 9000)
<commit_msg>Beautify :P<commit_after>const dgram = require('dgram')
const os = require('os')
const path = require('path')
const fs = require('fs')

const dragDrop = require('drag-drop')
const { remote, app } = require('electron')
const dialog = remote.dialog
const win = remote.getCurrentWindow()

const httpServer = require('./server')
const httpClient = require('https').request

const client = dgram.createSocket('udp4')
const server = dgram.createSocket('udp4')

const PORT = 4321
const MC = '224.0.0.1'

function send (o) {
  const message = Buffer.from(JSON.stringify(o))
  client.send(message, 0, message.length, PORT, MC)
}

//
// Dont accept arbitrary drops
//
dragDrop(document.body, () => {})

//
// Advertise a message
//
setInterval(() => {
  send({
    event: 'join',
    name: os.hostname().replace(/\.local/g, ''),
    platform: os.platform(),
    ctime: Date.now()
  })
}, 1500)

//
// Add a close button
//
const close = document.querySelector('.close')
close.addEventListener('click', () => {
  app.close()
})

const me = document.querySelector('#me')
me.textContent = os.hostname()

//
// Drop your avatar
//
dragDrop(me, (files) => {
  const reader = new window.FileReader()
  reader.onerror = err => {
    console.error(err)
  }
  reader.onload = e => {
    me.style.backgroundImage = 'url("' + e.target.result + '")'
    me.textContent = ''
    // fs.writeFileSync(
  }
  reader.readAsDataURL(files[0])
})

//
// Add our hostname to the `me` icon.
//

httpServer((req, res) => {
  const filename = req.headers['x-filename']

  if (req.url === '/upload') {
    const message = [
      'Do you want to accept the file',
      filename,
      'from',
      req.headers['x-from'] + '?'
    ].join(' ')

    const opts = {
      type: 'question',
      buttons: ['Ok', 'Cancel'],
      title: 'Confirm',
      message
    }

    const result = dialog.showMessageBox(win, opts)

    if (result === 0) {
      const dest = path.join(remote.app.getPath('downloads'), filename)
      const writeStream = fs.createWriteStream(dest)

      req.pipe(writeStream)
    }
  } else {
    // TODO serve the app so people can download it
  }
})

const registry = {}

function getData (src, cb) {
  const reader = new window.FileReader()
  reader.onerror = err => cb(err)
  reader.onload = e => cb(null, e.target.result)
  reader.readAsArrayBuffer(src)
}

function onFilesDropped (ip, files) {
  files.forEach(file => {
    const opts = {
      host: ip,
      port: 9988,
      path: '/upload',
      method: 'POST',
      rejectUnauthorized: false,
      headers: {
        'Content-Type': file.type,
        'x-filename': file.name,
        'x-from': os.hostname()
      }
    }

    getData(file, (err, data) => {
      if (err) return console.error(err)
      const req = httpClient(opts, res => {
        if (res.statusCode !== 200) {
          res.on('data', data => {
            console.error(res.statusCode, data)
          })
        }
      })

      req.end(Buffer.from(data))
    })
  })
}

//
// Create a tcp server
//

function joined (msg, rinfo) {
  const me = os.hostname().replace(/\.local/g, '')
  msg.name = msg.name.replace(/\.local/g, '')

  //
  // Don't show me my own machine as a peer
  //
  if (!process.env['DEBUG'] && msg.name === me) {
    return
  }

  //
  // If the peer is already rendered, just return
  //
  const selector = `[data-name="${msg.name}"]`
  if (document.querySelector(selector)) return

  //
  // Otherwise, create a peer and add it to the list.
  //
  const peers = document.querySelector('#peers')
  const peer = document.createElement('div')

  peer.className = 'peer adding adding-anim'
  peer.setAttribute('data-name', msg.name)
  peer.setAttribute('data-ip', rinfo.address)
  peer.setAttribute('data-platform', msg.platform)

  const avatar = document.createElement('div')
  avatar.className = 'avatar ' + msg.platform
  peer.appendChild(avatar)

  const name = document.createElement('address')
  name.textContent = msg.name
  name.title = rinfo.address
  peer.appendChild(name)

  peers.appendChild(peer)

  window.requestAnimationFrame(() => requestAnimationFrame(() => peer.classList.remove('adding')));
  peer.addEventListener('transitionend', e => {
    if (e.propertyName !== 'transform') return;
    peer.classList.remove('adding-anim');
  });
  //
  // Add a drag drop event to the peer
  //
  dragDrop(peer, (files) => {
    onFilesDropped(peer.getAttribute('data-ip'), files)
  })

  // remove inital empty message when finding peers
  const selectorEmptyState = document.querySelector('#empty-message')
  if (selectorEmptyState) selectorEmptyState.parentNode.removeChild(selectorEmptyState)
}

function parted (msg) {
  const selector = `.peer[data-name="${msg.name}"]`
  const peer = document.querySelector(selector)
  if (peer) peer.parentNode.removeChild(peer)
}

function cleanUp () {
  for (var key in registry) {
    if (registry[key] && (Date.now() - registry[key].ctime) > 9000) {
      parted(registry[key])
      registry[key] = null
    }
  }
}

server.on('error', (err) => {
  console.error(err)
  server.close()
})

server.on('message', (msg, rinfo) => {
  msg = JSON.parse(msg)
  if (!registry[msg.name] && msg.event === 'join') {
    joined(msg, rinfo)
  }
  registry[msg.name] = msg
})

server.on('listening', () => {
  console.log(`Listening on ${PORT}`)
})

server.bind(PORT)

setInterval(cleanUp, 9000)
<|endoftext|>


<commit_before>(function ($) {

	"use strict";

	var app = angular.module('RbsChange');

	/**
	 * Routes and URL definitions.
	 */
	app.config(['$provide', function ($provide)
	{
		$provide.decorator('RbsChange.UrlManager', ['$delegate', function ($delegate)
		{
			$delegate.model('Rbs_Tag').route('home', 'Rbs/Tag', { 'redirectTo': 'Rbs/Tag/Tag/'});
			$delegate.routesForModels(['Rbs_Tag_Tag']);
			return $delegate;
		}]);
	}]);

	__change.createEditorForModel('Rbs_Tag_Tag');

	//-------------------------------------------------------------------------
	//
	// Configuration and handlers.
	//
	//-------------------------------------------------------------------------

	/**
	 * Attach handlers:
	 * - create new tags in a Document's Editor (pre-save).
	 * - affect tags in a Document's Editor (post-save).
	 * - build predicates for "filter:hasTag" in <rbs-document-list/>.
	 */
	app.run(['RbsChange.TagService', 'RbsChange.Loading', 'RbsChange.Events', 'RbsChange.i18n', '$rootScope', '$q', '$timeout', function (TagService, Loading, Events, i18n, $rootScope, $q, $timeout) {

		// Create new and unsaved tags when an Editor is submitted.
		$rootScope.$on(Events.EditorPreSave, function (event, args) {
			angular.forEach(args.document.META$.tags, function (tag) {
				if (tag.unsaved) {
					args.promises.push(TagService.create(tag));
				}
			});
		});

		// Affect tags to a document that has just been saved in an Editor.
		$rootScope.$on(Events.EditorPostSave, function (event, args) {
			var	doc = args.document,
				tags = doc.META$.tags;
			if (angular.isArray(tags) && tags.length) {
				args.promises.push(TagService.setDocumentTags(doc, tags));
			}
		});

		// Load tags of the document being edited in an Editor.
		$rootScope.$on(Events.EditorLoaded, function (event, args) {
			var doc = args.document;
			if (doc.model !== 'Rbs_Tag_Tag') {
				args.promises.push(doc.loadTags());
			}
		});

		// Filter 'hasTag' for <rbs-document-list/>.
		$rootScope.$on(Events.DocumentListApplyFilter, function (event, args) {
			var	filter = args.filter,
				predicates = args.predicates,
				p, filterName, filterValue, tags;

			p = filter.indexOf(':');
			if (p === -1) {
				return;
			}

			filterName = filter.substring(0, p);
			if (filterName !== 'hasTag') {
				return;
			}

			filterValue = filter.substring(p+1);
			tags = filterValue.split(/,/);
			for (p=0 ; p<tags.length ; p++) {
				predicates.push({
					"op"  : "hasTag",
					"tag" : parseInt(tags[p], 10)
				});
			}
		});

		$rootScope.$on(Events.EditorFormButtonBarContents, function (event, args) {
			if (args.document.model !== 'Rbs_Tag_Tag') {
				args.contents.push('
' + i18n.trans('m.rbs.tag.admin.js.tags | ucf')  + '<rbs-tag-selector ng-model="document.META$.tags"></rbs-tag-selector>
');
			}
		});

		function affectTagToDocuments (tag, documents) {
			var promises = [];
			angular.forEach(documents, function (doc) {
				promises.push(TagService.addTagToDocument(tag, doc));
			});
			return $q.all(promises);
		}

		// Attach 'drop' handler on every <rbs-document-list/> to allow setting a Tag to the selected documents
		// with drag and drop.
		$(document).on({

			'dragover.rbs.tag' : function (e) {
				e.dataTransfer.dropEffect = "copy";
				e.preventDefault();
				e.stopPropagation();
			},

			'drop.rbs.tag' : function (e) {
				e.dataTransfer.dropEffect = "copy";
				e.preventDefault();
				e.stopPropagation();
				var	tag = e.dataTransfer.getData('Rbs/Tag'),
					documents = $(this).scope().selectedDocuments;
				if (tag && documents && documents.length) {
					$timeout(function () {
						Loading.start(i18n.trans('m.rbs.tag.admin.js.applying-tags | ucf | etc'));
						affectTagToDocuments(JSON.parse(tag), documents).then(function () {
							Loading.stop();
						});
					});
				}
			}

		}, 'rbs-document-list');

	}]);

	//-------------------------------------------------------------------------
	//
	// TagService
	//
	//-------------------------------------------------------------------------

	app.service('RbsChange.TagService', ['RbsChange.REST', 'RbsChange.Utils', '$q', '$http', function (REST, Utils, $q, $http) {

		function getIdArray (data) {
			var ids = [];
			angular.forEach(data, function (item) {
				ids.push(item.id);
			});
			return ids;
		}

		return {

			'getList' : function (defered) {
				var tags = [];
				REST.collection('Rbs_Tag_Tag', {'column': ['color','userTag'], 'limit': 100}).then(function (result) {
					angular.forEach(result.resources, function (r) {
						tags.push(r);
					});
					if (defered) {
						defered.resolve(tags);
					}
				});
				return tags;
			},

			'create' : function (tag) {
				tag.model = 'Rbs_Tag_Tag';
				tag.id = Utils.getTemporaryId();
				var promise = REST.save(tag);
				promise.then(function (created) {
					angular.extend(tag, created);
					delete tag.unsaved;
				});
				return promise;
			},

			'setDocumentTags' : function (doc, tags) {
				var q = $q.defer();
				$http.post(doc.getTagsUrl(), {"ids": getIdArray(tags)}, REST.getHttpConfig())
					.success(function (data) {
						q.resolve(doc);
					})
					.error(function errorCallback (data, status) {
						data.httpStatus = status;
						q.reject(data);
					});
				return q.promise;
			},

			'addTagToDocument' : function (tag, doc) {
				var q = $q.defer();
				$http.put(doc.getTagsUrl(), {"addIds": [tag.id]}, REST.getHttpConfig())
					.success(function (data) {
						if (!angular.isArray(doc.META$.tags)) {
							doc.META$.tags = [];
						}
						doc.META$.tags.push(tag);
						q.resolve(doc);
					})
					.error(function errorCallback (data, status) {
						data.httpStatus = status;
						q.reject(data);
					});
				return q.promise;
			}

		};

	}]);

})(window.jQuery);<commit_msg>Fixed loading indicator problem.<commit_after>(function ($) {

	"use strict";

	var app = angular.module('RbsChange');

	/**
	 * Routes and URL definitions.
	 */
	app.config(['$provide', function ($provide)
	{
		$provide.decorator('RbsChange.UrlManager', ['$delegate', function ($delegate)
		{
			$delegate.model('Rbs_Tag').route('home', 'Rbs/Tag', { 'redirectTo': 'Rbs/Tag/Tag/'});
			$delegate.routesForModels(['Rbs_Tag_Tag']);
			return $delegate;
		}]);
	}]);

	__change.createEditorForModel('Rbs_Tag_Tag');

	//-------------------------------------------------------------------------
	//
	// Configuration and handlers.
	//
	//-------------------------------------------------------------------------

	/**
	 * Attach handlers:
	 * - create new tags in a Document's Editor (pre-save).
	 * - affect tags in a Document's Editor (post-save).
	 * - build predicates for "filter:hasTag" in <rbs-document-list/>.
	 */
	app.run(['RbsChange.TagService', 'RbsChange.Loading', 'RbsChange.Events', 'RbsChange.i18n', '$rootScope', '$q', '$timeout', function (TagService, Loading, Events, i18n, $rootScope, $q, $timeout) {

		// Create new and unsaved tags when an Editor is submitted.
		$rootScope.$on(Events.EditorPreSave, function (event, args) {
			angular.forEach(args.document.META$.tags, function (tag) {
				if (tag.unsaved) {
					args.promises.push(TagService.create(tag));
				}
			});
		});

		// Affect tags to a document that has just been saved in an Editor.
		$rootScope.$on(Events.EditorPostSave, function (event, args) {
			var	doc = args.document,
				tags = doc.META$.tags;
			if (angular.isArray(tags) && tags.length) {
				args.promises.push(TagService.setDocumentTags(doc, tags));
			}
		});

		// Load tags of the document being edited in an Editor.
		$rootScope.$on(Events.EditorLoaded, function (event, args) {
			var doc = args.document;
			if (doc.model !== 'Rbs_Tag_Tag') {
				args.promises.push(doc.loadTags());
			}
		});

		// Filter 'hasTag' for <rbs-document-list/>.
		$rootScope.$on(Events.DocumentListApplyFilter, function (event, args) {
			var	filter = args.filter,
				predicates = args.predicates,
				p, filterName, filterValue, tags;

			p = filter.indexOf(':');
			if (p === -1) {
				return;
			}

			filterName = filter.substring(0, p);
			if (filterName !== 'hasTag') {
				return;
			}

			filterValue = filter.substring(p+1);
			tags = filterValue.split(/,/);
			for (p=0 ; p<tags.length ; p++) {
				predicates.push({
					"op"  : "hasTag",
					"tag" : parseInt(tags[p], 10)
				});
			}
		});

		$rootScope.$on(Events.EditorFormButtonBarContents, function (event, args) {
			if (args.document.model !== 'Rbs_Tag_Tag') {
				args.contents.push('
' + i18n.trans('m.rbs.tag.admin.js.tags | ucf')  + '<rbs-tag-selector ng-model="document.META$.tags"></rbs-tag-selector>
');
			}
		});

		function affectTagToDocuments (tag, documents) {
			var promises = [];
			angular.forEach(documents, function (doc) {
				promises.push(TagService.addTagToDocument(tag, doc));
			});
			return $q.all(promises);
		}

		// Attach 'drop' handler on every <rbs-document-list/> to allow setting a Tag to the selected documents
		// with drag and drop.
		$(document).on({

			'dragover.rbs.tag' : function (e) {
				e.dataTransfer.dropEffect = "copy";
				e.preventDefault();
				e.stopPropagation();
			},

			'drop.rbs.tag' : function (e) {
				e.dataTransfer.dropEffect = "copy";
				e.preventDefault();
				e.stopPropagation();
				var	tag = e.dataTransfer.getData('Rbs/Tag'),
					documents = $(this).scope().selectedDocuments;
				if (tag && documents && documents.length) {
					$timeout(function () {
						Loading.start(i18n.trans('m.rbs.tag.admin.js.applying-tags | ucf | etc'));
						affectTagToDocuments(JSON.parse(tag), documents).then(
							function () {
								Loading.stop();
							},
							function () {
								// TODO Notify user.
								Loading.stop();
							}
						);
					});
				}
			}

		}, 'rbs-document-list');

	}]);

	//-------------------------------------------------------------------------
	//
	// TagService
	//
	//-------------------------------------------------------------------------

	app.service('RbsChange.TagService', ['RbsChange.REST', 'RbsChange.Utils', '$q', '$http', function (REST, Utils, $q, $http) {

		function getIdArray (data) {
			var ids = [];
			angular.forEach(data, function (item) {
				ids.push(item.id);
			});
			return ids;
		}

		return {

			'getList' : function (defered) {
				var tags = [];
				REST.collection('Rbs_Tag_Tag', {'column': ['color','userTag'], 'limit': 100}).then(function (result) {
					angular.forEach(result.resources, function (r) {
						tags.push(r);
					});
					if (defered) {
						defered.resolve(tags);
					}
				});
				return tags;
			},

			'create' : function (tag) {
				tag.model = 'Rbs_Tag_Tag';
				tag.id = Utils.getTemporaryId();
				var promise = REST.save(tag);
				promise.then(function (created) {
					angular.extend(tag, created);
					delete tag.unsaved;
				});
				return promise;
			},

			'setDocumentTags' : function (doc, tags) {
				var q = $q.defer();
				$http.post(doc.getTagsUrl(), {"ids": getIdArray(tags)}, REST.getHttpConfig())
					.success(function (data) {
						q.resolve(doc);
					})
					.error(function errorCallback (data, status) {
						data.httpStatus = status;
						q.reject(data);
					});
				return q.promise;
			},

			'addTagToDocument' : function (tag, doc) {
				var q = $q.defer();
				$http.put(doc.getTagsUrl(), {"addIds": [tag.id]}, REST.getHttpConfig())
					.success(function (data) {
						if (!angular.isArray(doc.META$.tags)) {
							doc.META$.tags = [];
						}
						doc.META$.tags.push(tag);
						q.resolve(doc);
					})
					.error(function errorCallback (data, status) {
						data.httpStatus = status;
						q.reject(data);
					});
				return q.promise;
			}

		};

	}]);

})(window.jQuery);<|endoftext|>


<commit_before>class PGroup {
	constructor(array) {
		this.members = array;
	}

	add(element) {
		return new PGroup(this.members.slice().push(element));
	}

	delete(element) {
		return new PGroup(this.members.filter(e => e !== element));
	}

	has(element) {
		return this.members.includes(element);
	}
}

PGroup.empty = new PGroup([]);
<commit_msg>Fix add and delete methods<commit_after>class PGroup {
	constructor(array) {
		this.members = array;
	}

	add(element) {
		if (this.has(element)) return this;
		return new PGroup(this.members.concat([element]));
	}

	delete(element) {
		if (!this.has(element)) return this;
		return new PGroup(this.members.filter(e => e !== element));
	}

	has(element) {
		return this.members.includes(element);
	}
}

PGroup.empty = new PGroup([]);
<|endoftext|>


<commit_before>import React from 'react';
import {Link} from 'react-router-dom';
import PropTypes from 'prop-types';
import {DropdownItem, DropdownMenu, DropdownToggle, Nav, NavItem, NavLink, Container} from 'reactstrap';
import {LIGHT_THEME, DARK_THEME} from '../constants';
import FontAwesome from 'react-fontawesome';

import {
  AppAside,
  AppFooter,
  AppHeader,
  AppSidebar,
  AppSidebarFooter,
  AppSidebarForm,
  AppSidebarHeader,
  AppSidebarMinimizer,
  AppSidebarNav,
  AppSidebarToggler,
  AppNavbarBrand,
  AppHeaderDropdown
} from '@coreui/react';

import SearchBar from './SearchBar';

import logo from '../images/logo-new.svg';

const HEADER_NAV_ITEMS = [
  {name: "Dashboard", to: "/embark", icon: 'tachometer'},
  {name: "Deployment", to: "/embark/deployment", icon: "arrow-up"},
  {name: "Contracts", to: "/embark/contracts", icon: "file-text"},
  {name: "Explorer", to: "/embark/explorer/overview", icon: "compass"},
  {name: "Editor", to: "/embark/editor", icon: "codepen"},
  {name: "Utils", to: "/embark/utilities/converter", icon: "cog"}
];

const SIDEBAR_NAV_ITEMS = {
  "/embark/explorer" : {items: [
    {url: "/embark/explorer/overview", icon: "fa fa-signal", name: "Overview"},
    {url: "/embark/explorer/accounts", icon: "fa fa-users", name: "Accounts"},
    {url: "/embark/explorer/blocks", icon: "fa fa-stop", name: "Blocks"},
    {url: "/embark/explorer/transactions", icon: "fa fa-tree", name: "Transactions"}
  ]},
  "/embark/utilities/": {items: [
    {url: "/embark/utilities/converter", icon: "fa fa-plug", name: "Converter"},
    {url: "/embark/utilities/communication", icon: "fa fa-phone", name: "Communication"},
    {url: "/embark/utilities/ens", icon: "fa fa-circle", name: "ENS"},
    {url: "/embark/utilities/sign-and-verify", icon: "fa fa-edit", name: "Sign & Verify"},
    {url: "/embark/utilities/transaction-decoder", icon: "fa fa-edit", name: "Transaction Decoder"}
  ]}
};

const removeCssClasses = () => {
  document.body.classList.remove('sidebar-fixed');
  document.body.classList.remove('sidebar-lg-show');
}

const getSidebar = (location) => {
  const currentItem = Object.keys(SIDEBAR_NAV_ITEMS).find(path => location.pathname.startsWith(path));
  return currentItem && SIDEBAR_NAV_ITEMS[currentItem];
}

function searchTheExplorer(value) {
  // TODO: search
}

const Layout = ({children, logout, location, toggleTheme, currentTheme}) => {
  const sidebar = getSidebar(location);
  if (!sidebar) {
    removeCssClasses();
  }
  return (

      <AppHeader fixed>
        <AppSidebarToggler className="d-lg-none" display="md" mobile />
        <AppNavbarBrand
          full={{ src: logo, width: 50, height: 50, alt: 'Embark Logo' }}
          minimized={{ src: logo, width: 30, height: 30, alt: 'Embark Logo' }}
        />
        {sidebar && <AppSidebarToggler className="d-md-down-none" display="lg" />}

          {HEADER_NAV_ITEMS.map((item) => {
            return (
              <NavItem className="px-3" key={item.to}>
                <NavLink exact tag={Link} to={item.to}>
                  <FontAwesome className="mr-2" name={item.icon} />
                  {item.name}
                </NavLink>
              </NavItem>
            )
          })}

          <SearchBar searchSubmit={searchValue => searchTheExplorer(searchValue)}/>
          <AppHeaderDropdown direction="down">
            <DropdownToggle nav>

            </DropdownToggle>
            <DropdownMenu right style={{ right: 'auto' }}>
              <DropdownItem className="text-capitalize" onClick={() => toggleTheme()}>
                <FontAwesome name={currentTheme === DARK_THEME ? 'sun-o' : 'moon-o'} />
                {currentTheme === DARK_THEME ? LIGHT_THEME : DARK_THEME} Mode
              </DropdownItem>
              <DropdownItem onClick={logout}><FontAwesome name="lock" /> Logout</DropdownItem>
            </DropdownMenu>
          </AppHeaderDropdown>

      </AppHeader>

        {sidebar &&
          <AppSidebar fixed display="lg">
            <AppSidebarHeader />
            <AppSidebarForm />
            <AppSidebarNav navConfig={sidebar} location={location} />
            <AppSidebarFooter />
            <AppSidebarMinimizer />
          </AppSidebar>
        }

          <Container fluid className="h-100" style={{marginTop: '24px'}}>
            {children}
          </Container>

        <AppAside fixed>
        </AppAside>

      <AppFooter>

          Embark
          Documentation
           |
          Github

      </AppFooter>

  );
}

Layout.propTypes = {
  children: PropTypes.element,
  tabs: PropTypes.arrayOf(PropTypes.object),
  location: PropTypes.object,
  logout: PropTypes.func,
  toggleTheme: PropTypes.func,
  currentTheme: PropTypes.string
};

export default Layout;
<commit_msg>Remove toggler<commit_after>import React from 'react';
import {Link} from 'react-router-dom';
import PropTypes from 'prop-types';
import {DropdownItem, DropdownMenu, DropdownToggle, Nav, NavItem, NavLink, Container} from 'reactstrap';
import {LIGHT_THEME, DARK_THEME} from '../constants';
import FontAwesome from 'react-fontawesome';

import {
  AppAside,
  AppFooter,
  AppHeader,
  AppSidebar,
  AppSidebarFooter,
  AppSidebarForm,
  AppSidebarHeader,
  AppSidebarMinimizer,
  AppSidebarNav,
  AppNavbarBrand,
  AppHeaderDropdown
} from '@coreui/react';

import SearchBar from './SearchBar';

import logo from '../images/logo-new.svg';

const HEADER_NAV_ITEMS = [
  {name: "Dashboard", to: "/embark", icon: 'tachometer'},
  {name: "Deployment", to: "/embark/deployment", icon: "arrow-up"},
  {name: "Contracts", to: "/embark/contracts", icon: "file-text"},
  {name: "Explorer", to: "/embark/explorer/overview", icon: "compass"},
  {name: "Editor", to: "/embark/editor", icon: "codepen"},
  {name: "Utils", to: "/embark/utilities/converter", icon: "cog"}
];

const SIDEBAR_NAV_ITEMS = {
  "/embark/explorer" : {items: [
    {url: "/embark/explorer/overview", icon: "fa fa-signal", name: "Overview"},
    {url: "/embark/explorer/accounts", icon: "fa fa-users", name: "Accounts"},
    {url: "/embark/explorer/blocks", icon: "fa fa-stop", name: "Blocks"},
    {url: "/embark/explorer/transactions", icon: "fa fa-tree", name: "Transactions"}
  ]},
  "/embark/utilities/": {items: [
    {url: "/embark/utilities/converter", icon: "fa fa-plug", name: "Converter"},
    {url: "/embark/utilities/communication", icon: "fa fa-phone", name: "Communication"},
    {url: "/embark/utilities/ens", icon: "fa fa-circle", name: "ENS"},
    {url: "/embark/utilities/sign-and-verify", icon: "fa fa-edit", name: "Sign & Verify"},
    {url: "/embark/utilities/transaction-decoder", icon: "fa fa-edit", name: "Transaction Decoder"}
  ]}
};

const removeCssClasses = () => {
  document.body.classList.remove('sidebar-fixed');
  document.body.classList.remove('sidebar-lg-show');
}

const getSidebar = (location) => {
  const currentItem = Object.keys(SIDEBAR_NAV_ITEMS).find(path => location.pathname.startsWith(path));
  return currentItem && SIDEBAR_NAV_ITEMS[currentItem];
}

function searchTheExplorer(value) {
  // TODO: search
}

const Layout = ({children, logout, location, toggleTheme, currentTheme}) => {
  const sidebar = getSidebar(location);
  if (!sidebar) {
    removeCssClasses();
  }
  return (

      <AppHeader fixed>
        <AppNavbarBrand className="mx-3"
          full={{ src: logo, width: 50, height: 50, alt: 'Embark Logo' }}
          minimized={{ src: logo, width: 30, height: 30, alt: 'Embark Logo' }}
        />

          {HEADER_NAV_ITEMS.map((item) => {
            return (
              <NavItem className="px-3" key={item.to}>
                <NavLink exact tag={Link} to={item.to}>
                  <FontAwesome className="mr-2" name={item.icon} />
                  {item.name}
                </NavLink>
              </NavItem>
            )
          })}

          <SearchBar searchSubmit={searchValue => searchTheExplorer(searchValue)}/>
          <AppHeaderDropdown direction="down">
            <DropdownToggle nav>

            </DropdownToggle>
            <DropdownMenu right style={{ right: 'auto' }}>
              <DropdownItem className="text-capitalize" onClick={() => toggleTheme()}>
                <FontAwesome name={currentTheme === DARK_THEME ? 'sun-o' : 'moon-o'} />
                {currentTheme === DARK_THEME ? LIGHT_THEME : DARK_THEME} Mode
              </DropdownItem>
              <DropdownItem onClick={logout}><FontAwesome name="lock" /> Logout</DropdownItem>
            </DropdownMenu>
          </AppHeaderDropdown>

      </AppHeader>

        {sidebar &&
          <AppSidebar fixed display="lg">
            <AppSidebarHeader />
            <AppSidebarForm />
            <AppSidebarNav navConfig={sidebar} location={location} />
            <AppSidebarFooter />
            <AppSidebarMinimizer />
          </AppSidebar>
        }

          <Container fluid className="h-100" style={{marginTop: '24px'}}>
            {children}
          </Container>

        <AppAside fixed>
        </AppAside>

      <AppFooter>

          Embark
          Documentation
           |
          Github

      </AppFooter>

  );
}

Layout.propTypes = {
  children: PropTypes.element,
  tabs: PropTypes.arrayOf(PropTypes.object),
  location: PropTypes.object,
  logout: PropTypes.func,
  toggleTheme: PropTypes.func,
  currentTheme: PropTypes.string
};

export default Layout;
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { computed } from '@ember/object';
import { inject as service } from '@ember/service';

export default Component.extend({
  pinnedFlights: service(),

  tagName: '',

  pinned: computed('pinnedFlights.pinned.[]', 'flightId', function () {
    return this.pinnedFlights.pinned.includes(this.flightId);
  }),

  actions: {
    toggle() {
      this.pinnedFlights.toggle(this.flightId);
    },
  },
});
<commit_msg>PinButton: Convert to ES6 class<commit_after>import Component from '@ember/component';
import { action, computed } from '@ember/object';
import { inject as service } from '@ember/service';

export default class PinButton extends Component {
  @service pinnedFlights;

  tagName = '';

  @computed('pinnedFlights.pinned.[]', 'flightId')
  get pinned() {
    return this.pinnedFlights.pinned.includes(this.flightId);
  }

  @action toggle() {
    this.pinnedFlights.toggle(this.flightId);
  }
}
<|endoftext|>


<commit_before>/**
 * crown-and-anchor.js
 * 크라운 앤 앵커 게임
 *
 * extract code from a learn javascirpt book
 * 소스코드는 러닝자바스크립트 책의 내용을 참조하였습니다.
 */

const _face = ['crown', 'anchor', 'heart', 'spade', 'club', 'diamond'];
let _bets, _funds, _round, _totalBet;

const $containerReady = $('#container-ready'),
    $containerMain = $('#container-main'),
    $startBtn = $containerReady.find('#startBtn'),
    $bettingBtn = $containerMain.find('#bettingBtn'),
    $fundsDiv = $containerMain.find('#funds'),
    $roundDiv = $containerMain.find('#round'),
    $totalBetDiv = $containerMain.find('#totalBet'),
    $crownDiv = $containerMain.find('#crown'),
    $anchorDiv = $containerMain.find('#anchor'),
    $heartDiv = $containerMain.find('#heart'),
    $spadeDiv = $containerMain.find('#spade'),
    $clubDiv = $containerMain.find('#club'),
    $diamondDiv = $containerMain.find('#diamond');

/**
 * m이상 n이하의 무작위 정수를 반환합니다.
 *
 * @param {number} m
 * @param {number} n
 */
const _rand = (m, n) => m + Math.floor((n - m + 1) * Math.random());

/**
 * 크라운 앤 앵커 게임의 여섯 가지 도형 중 하나를 무작위 반환합니다.
 */
const _randFace = () => _face[_rand(0, 5)];

/**
 * 배팅합니다.
 */
const _betting = face => {
    if (_funds < 1) return;
    ++_totalBet;
    _bets[face] = _bets[face] + 1;
    --_funds;
    _setFunds();
    _setTotalBet();
    _setBadge(face);
    console.log(Object.keys(_bets).map(_face => `${_face}: ${_bets[_face]} pencs`).join(', ') + `(total: ${_totalBet} pencs)`);
};

/**
 * 주사위를 굴립니다.
 *
 * @returns {array}
 */
const _rollTheDice = () => {
    const hand = [];
    for (let i = 0; i < 3; i++) {
        const face = _randFace();
        hand.push(face);
        _showDice(face, i);
    }
    console.log(`hand: ${hand.join(', ')}`);

    return hand;
};

const _setBadge = face => {
    $containerMain.find('#' + face).find('.badge').html(_bets[face]);
};

const _initBadge = () => {
    $containerMain.find('.badge').empty();
};

/**
 * 주사위를 보여줍니다.
 *
 * @param {string} face
 * @param {number} i
 */
const _showDice = (face, i) => {
    let str;
    if (face === _face[0]) {
        str = '👑';
    } else if (face === _face[1]) {
        str = '⚓';
    } else if (face === _face[2]) {
        str = '❤';
    } else if (face === _face[3]) {
        str = '♠';
    } else if (face === _face[4]) {
        str = '☘';
    } else if (face === _face[5]) {
        str = '🔶';
    }
    $containerMain.find('#dice' + i).html(`<h1>${str}</h1>`);
};

/**
 * 딴 돈을 가져옵니다.
 *
 * @param {Object} bets
 * @param {array} hand
 */
const _checkWinnings = (bets, hand) => {
    let winnings = 0;
    for (let die = 0, len = hand.length; die < len; die++) {
        let face = hand[die];
        if (bets[face] > 0) winnings = winnings + bets[face];
    }
    _funds = _funds + winnings;
    _setFunds();
    _setRound();
    _initBets();
    _showWinnings(winnings);
    console.log(`winnings: ${winnings}`);
};

/**
 * 딴 돈을 표시합니다.
 *
 * @param {number} winnings
 */
const _showWinnings = winnings => {
    if (winnings) {
        $containerMain.find('#winnings').html(winnings);
        $containerMain.find('.winnings-wapper').show().css('display', 'flex');
    } else {
        $containerMain.find('.winnings-wapper').hide();
    }
};

/**
 * 게임을 시작합니다.
 */
const _play = () => {
    _round++;
    console.log(`round ${_round}:`);
    console.log(`starting funds: ${_funds}p`);
    const hand = _rollTheDice();
    _checkWinnings(_bets, hand);
};

/**
 * Start button handler
 */
const _startHandler = () => {
    $('#container-ready').slideUp('fast');
    $('#container-main').show();
    _init();
};

/**
 * Betting button handler
 */
const _bettingHandler = () => {
    if (_funds > 0) _play();
    else _end();
};

/**
 * Event bind
 */
const _bind = () => {
    $startBtn.on('click', _startHandler);
    $bettingBtn.on('click', _bettingHandler);
    $crownDiv.on('click', () => { _betting(_face[0]); });
    $anchorDiv.on('click', () => { _betting(_face[1]); });
    $heartDiv.on('click', () => { _betting(_face[2]); });
    $spadeDiv.on('click', () => { _betting(_face[3]); });
    $clubDiv.on('click', () => { _betting(_face[4]); });
    $diamondDiv.on('click', () => { _betting(_face[5]); });
};

/**
 * 게임을 초기화 합니다.
 */
const _init = () => {
    _funds = 50;
    _round = 1;
    _initBets();
    _setFunds();
    _setRound();
};

/**
 * 베팅을 초기화 합니다.
 */
const _initBets = () => {
    _totalBet = 0;
    _bets = { crown: 0, anchor: 0, heart: 0, spade: 0, club: 0, diamond: 0 };
    _setTotalBet();
    _initBadge();
};

const _setFunds = () => {
    $fundsDiv.html(_funds);
};

const _setRound = () => {
    $roundDiv.html(_round);
};

const _setTotalBet = () => {
    $totalBetDiv.html(_totalBet);
};

/**
 * 게임을 끝냅니다.
 */
const _end = () => {
    $bettingBtn.hide();
    console.log(`ending funds: ${_funds}`);
};

(() => {
    _bind();
})();<commit_msg>Update description<commit_after>/**
 * crown-and-anchor.js
 * 크라운 앤 앵커 게임
 *
 * extract code from a learning javascirpt book
 * 소스코드는 러닝자바스크립트 책의 내용을 참조하였습니다.
 */

const _face = ['crown', 'anchor', 'heart', 'spade', 'club', 'diamond'];
let _bets, _funds, _round, _totalBet;

const $containerReady = $('#container-ready'),
    $containerMain = $('#container-main'),
    $startBtn = $containerReady.find('#startBtn'),
    $bettingBtn = $containerMain.find('#bettingBtn'),
    $fundsDiv = $containerMain.find('#funds'),
    $roundDiv = $containerMain.find('#round'),
    $totalBetDiv = $containerMain.find('#totalBet'),
    $crownDiv = $containerMain.find('#crown'),
    $anchorDiv = $containerMain.find('#anchor'),
    $heartDiv = $containerMain.find('#heart'),
    $spadeDiv = $containerMain.find('#spade'),
    $clubDiv = $containerMain.find('#club'),
    $diamondDiv = $containerMain.find('#diamond');

/**
 * m이상 n이하의 무작위 정수를 반환합니다.
 *
 * @param {number} m
 * @param {number} n
 */
const _rand = (m, n) => m + Math.floor((n - m + 1) * Math.random());

/**
 * 크라운 앤 앵커 게임의 여섯 가지 도형 중 하나를 무작위 반환합니다.
 */
const _randFace = () => _face[_rand(0, 5)];

/**
 * 배팅합니다.
 */
const _betting = face => {
    if (_funds < 1) return;
    ++_totalBet;
    _bets[face] = _bets[face] + 1;
    --_funds;
    _setFunds();
    _setTotalBet();
    _setBadge(face);
    console.log(Object.keys(_bets).map(_face => `${_face}: ${_bets[_face]} pencs`).join(', ') + `(total: ${_totalBet} pencs)`);
};

/**
 * 주사위를 굴립니다.
 *
 * @returns {array}
 */
const _rollTheDice = () => {
    const hand = [];
    for (let i = 0; i < 3; i++) {
        const face = _randFace();
        hand.push(face);
        _showDice(face, i);
    }
    console.log(`hand: ${hand.join(', ')}`);

    return hand;
};

const _setBadge = face => {
    $containerMain.find('#' + face).find('.badge').html(_bets[face]);
};

const _initBadge = () => {
    $containerMain.find('.badge').empty();
};

/**
 * 주사위를 보여줍니다.
 *
 * @param {string} face
 * @param {number} i
 */
const _showDice = (face, i) => {
    let str;
    if (face === _face[0]) {
        str = '👑';
    } else if (face === _face[1]) {
        str = '⚓';
    } else if (face === _face[2]) {
        str = '❤';
    } else if (face === _face[3]) {
        str = '♠';
    } else if (face === _face[4]) {
        str = '☘';
    } else if (face === _face[5]) {
        str = '🔶';
    }
    $containerMain.find('#dice' + i).html(`<h1>${str}</h1>`);
};

/**
 * 딴 돈을 가져옵니다.
 *
 * @param {Object} bets
 * @param {array} hand
 */
const _checkWinnings = (bets, hand) => {
    let winnings = 0;
    for (let die = 0, len = hand.length; die < len; die++) {
        let face = hand[die];
        if (bets[face] > 0) winnings = winnings + bets[face];
    }
    _funds = _funds + winnings;
    _setFunds();
    _setRound();
    _initBets();
    _showWinnings(winnings);
    console.log(`winnings: ${winnings}`);
};

/**
 * 딴 돈을 표시합니다.
 *
 * @param {number} winnings
 */
const _showWinnings = winnings => {
    if (winnings) {
        $containerMain.find('#winnings').html(winnings);
        $containerMain.find('.winnings-wapper').show().css('display', 'flex');
    } else {
        $containerMain.find('.winnings-wapper').hide();
    }
};

/**
 * 게임을 시작합니다.
 */
const _play = () => {
    _round++;
    console.log(`round ${_round}:`);
    console.log(`starting funds: ${_funds}p`);
    const hand = _rollTheDice();
    _checkWinnings(_bets, hand);
};

/**
 * Start button handler
 */
const _startHandler = () => {
    $('#container-ready').slideUp('fast');
    $('#container-main').show();
    _init();
};

/**
 * Betting button handler
 */
const _bettingHandler = () => {
    if (_funds > 0) _play();
    else _end();
};

/**
 * Event bind
 */
const _bind = () => {
    $startBtn.on('click', _startHandler);
    $bettingBtn.on('click', _bettingHandler);
    $crownDiv.on('click', () => { _betting(_face[0]); });
    $anchorDiv.on('click', () => { _betting(_face[1]); });
    $heartDiv.on('click', () => { _betting(_face[2]); });
    $spadeDiv.on('click', () => { _betting(_face[3]); });
    $clubDiv.on('click', () => { _betting(_face[4]); });
    $diamondDiv.on('click', () => { _betting(_face[5]); });
};

/**
 * 게임을 초기화 합니다.
 */
const _init = () => {
    _funds = 50;
    _round = 1;
    _initBets();
    _setFunds();
    _setRound();
};

/**
 * 베팅을 초기화 합니다.
 */
const _initBets = () => {
    _totalBet = 0;
    _bets = { crown: 0, anchor: 0, heart: 0, spade: 0, club: 0, diamond: 0 };
    _setTotalBet();
    _initBadge();
};

const _setFunds = () => {
    $fundsDiv.html(_funds);
};

const _setRound = () => {
    $roundDiv.html(_round);
};

const _setTotalBet = () => {
    $totalBetDiv.html(_totalBet);
};

/**
 * 게임을 끝냅니다.
 */
const _end = () => {
    $bettingBtn.hide();
    console.log(`ending funds: ${_funds}`);
};

(() => {
    _bind();
})();<|endoftext|>


<commit_before>var quotes = [
    'Oh god how did this get here I am not good with computer.',
    'Hello everybody! I hope you have a good day!',
    'uggghhhh..... What\'s with all this /green/???',
    'Green is my favorite color 0.0',
    'Hm.... I wonder where all my friends are...',
    'Chara just wished that I have a good time!',
    'Dang! It didn\'t work!',
    'Just little old me~',
    'I wonder what happened...',
    'I hope Charat works today!',
];

// History.js
(function(window,undefined){

    // Prepare
    var History = window.History; // Note: We are using a capital H instead of a lower h
    if ( !History.enabled ) {
         // History.js is disabled for this browser.
         // This is because we can optionally choose to support HTML4 browsers or not.
        return false;
    }

    // Bind to StateChange Event
    History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
        var State = History.getState(); // Note: We are using History.getState() instead of event.state
        History.log(State.data, State.title, State.url);
    });

    // Change our States
    History.pushState({state:1}, "State 1", "?state=1"); // logs {state:1}, "State 1", "?state=1"
    History.pushState({state:2}, "State 2", "?state=2"); // logs {state:2}, "State 2", "?state=2"
    History.replaceState({state:3}, "State 3", "?state=3"); // logs {state:3}, "State 3", "?state=3"
    History.pushState(null, null, "?state=4"); // logs {}, '', "?state=4"
    History.back(); // logs {state:3}, "State 3", "?state=3"
    History.back(); // logs {state:1}, "State 1", "?state=1"
    History.back(); // logs {}, "Home Page", "?"
    History.go(2); // logs {state:3}, "State 3", "?state=3"

})(window);

$.fn.exists = function(){return this.length>0;}

function cmobile() {
    if (navigator.userAgent.indexOf('Android')!=-1 || navigator.userAgent.indexOf('iPhone')!=-1 || navigator.userAgent.indexOf('Nintendo 3DS')!=-1 || navigator.userAgent.indexOf('Nintendo DSi')!=-1 || window.innerWidth<=630) {
        return true;
    } else {
        return false;
    }
}

function screenCheck() {
    if (cmobile()){
        $(document.body).addClass('mobile');
        $(document.body).removeClass('nobile');
    } else if (window.innerWidth<=950){
        $(document.body).addClass('nobile');
        $(document.body).removeClass('mobile');
    } else  {
        $(document.body).removeClass('mobile');
        $(document.body).removeClass('nobile');
    }
}

$(document).ready(function() {
    var quote = quotes[Math.floor(Math.random()*quotes.length)];
    $('#quote').html(quote);

    if(navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false) {
        $('meta[name=viewport]').attr('content', 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />');
    }

    /* Topbar Menu */
    $('#toptitle').click(function() {
        if ($('body.menu').exists()) {
            $(document.body).removeClass('menu');
        } else {
            $(document.body).addClass('menu');
        }
    });
    $('#topbar').on("mouseleave", function(){
        if ($('body.menu').exists()) {
            $(document.body).removeClass('menu');
        }
    });
});

$(window).load(function() {
    screenCheck();
    $(window).resize(function() {
        screenCheck();
    });
});<commit_msg>History JS<commit_after>var quotes = [
    'Oh god how did this get here I am not good with computer.',
    'Hello everybody! I hope you have a good day!',
    'uggghhhh..... What\'s with all this /green/???',
    'Green is my favorite color 0.0',
    'Hm.... I wonder where all my friends are...',
    'Chara just wished that I have a good time!',
    'Dang! It didn\'t work!',
    'Just little old me~',
    'I wonder what happened...',
    'I hope Charat works today!',
];

// History.js
(function(a,b){"use strict";var c=a.History=a.History||{},d=a.jQuery;if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={bind:function(a,b,c){d(a).bind(b,c)},trigger:function(a,b,c){d(a).trigger(b,c)},extractEventData:function(a,c,d){var e=c&&c.originalEvent&&c.originalEvent[a]||d&&d[a]||b;return e},onDomLoad:function(a){d(a)}},typeof c.init!="undefined"&&c.init()})(window)
(function(a,b){"use strict";var c=a.document,d=a.setTimeout||d,e=a.clearTimeout||e,f=a.setInterval||f,g=a.History=a.History||{};if(typeof g.initHtml4!="undefined")throw new Error("History.js HTML4 Support has already been loaded...");g.initHtml4=function(){if(typeof g.initHtml4.initialized!="undefined")return!1;g.initHtml4.initialized=!0,g.enabled=!0,g.savedHashes=[],g.isLastHash=function(a){var b=g.getHashByIndex(),c;return c=a===b,c},g.saveHash=function(a){return g.isLastHash(a)?!1:(g.savedHashes.push(a),!0)},g.getHashByIndex=function(a){var b=null;return typeof a=="undefined"?b=g.savedHashes[g.savedHashes.length-1]:a<0?b=g.savedHashes[g.savedHashes.length+a]:b=g.savedHashes[a],b},g.discardedHashes={},g.discardedStates={},g.discardState=function(a,b,c){var d=g.getHashByState(a),e;return e={discardedState:a,backState:c,forwardState:b},g.discardedStates[d]=e,!0},g.discardHash=function(a,b,c){var d={discardedHash:a,backState:c,forwardState:b};return g.discardedHashes[a]=d,!0},g.discardedState=function(a){var b=g.getHashByState(a),c;return c=g.discardedStates[b]||!1,c},g.discardedHash=function(a){var b=g.discardedHashes[a]||!1;return b},g.recycleState=function(a){var b=g.getHashByState(a);return g.discardedState(a)&&delete g.discardedStates[b],!0},g.emulated.hashChange&&(g.hashChangeInit=function(){g.checkerFunction=null;var b="",d,e,h,i;return g.isInternetExplorer()?(d="historyjs-iframe",e=c.createElement("iframe"),e.setAttribute("id",d),e.style.display="none",c.body.appendChild(e),e.contentWindow.document.open(),e.contentWindow.document.close(),h="",i=!1,g.checkerFunction=function(){if(i)return!1;i=!0;var c=g.getHash()||"",d=g.unescapeHash(e.contentWindow.document.location.hash)||"";return c!==b?(b=c,d!==c&&(h=d=c,e.contentWindow.document.open(),e.contentWindow.document.close(),e.contentWindow.document.location.hash=g.escapeHash(c)),g.Adapter.trigger(a,"hashchange")):d!==h&&(h=d,g.setHash(d,!1)),i=!1,!0}):g.checkerFunction=function(){var c=g.getHash();return c!==b&&(b=c,g.Adapter.trigger(a,"hashchange")),!0},g.intervalList.push(f(g.checkerFunction,g.options.hashChangeInterval)),!0},g.Adapter.onDomLoad(g.hashChangeInit)),g.emulated.pushState&&(g.onHashChange=function(b){var d=b&&b.newURL||c.location.href,e=g.getHashByUrl(d),f=null,h=null,i=null,j;return g.isLastHash(e)?(g.busy(!1),!1):(g.doubleCheckComplete(),g.saveHash(e),e&&g.isTraditionalAnchor(e)?(g.Adapter.trigger(a,"anchorchange"),g.busy(!1),!1):(f=g.extractState(g.getFullUrl(e||c.location.href,!1),!0),g.isLastSavedState(f)?(g.busy(!1),!1):(h=g.getHashByState(f),j=g.discardedState(f),j?(g.getHashByIndex(-2)===g.getHashByState(j.forwardState)?g.back(!1):g.forward(!1),!1):(g.pushState(f.data,f.title,f.url,!1),!0))))},g.Adapter.bind(a,"hashchange",g.onHashChange),g.pushState=function(b,d,e,f){if(g.getHashByUrl(e))throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==!1&&g.busy())return g.pushQueue({scope:g,callback:g.pushState,args:arguments,queue:f}),!1;g.busy(!0);var h=g.createStateObject(b,d,e),i=g.getHashByState(h),j=g.getState(!1),k=g.getHashByState(j),l=g.getHash();return g.storeState(h),g.expectedStateId=h.id,g.recycleState(h),g.setTitle(h),i===k?(g.busy(!1),!1):i!==l&&i!==g.getShortUrl(c.location.href)?(g.setHash(i,!1),!1):(g.saveState(h),g.Adapter.trigger(a,"statechange"),g.busy(!1),!0)},g.replaceState=function(a,b,c,d){if(g.getHashByUrl(c))throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(d!==!1&&g.busy())return g.pushQueue({scope:g,callback:g.replaceState,args:arguments,queue:d}),!1;g.busy(!0);var e=g.createStateObject(a,b,c),f=g.getState(!1),h=g.getStateByIndex(-2);return g.discardState(f,e,h),g.pushState(e.data,e.title,e.url,!1),!0}),g.emulated.pushState&&g.getHash()&&!g.emulated.hashChange&&g.Adapter.onDomLoad(function(){g.Adapter.trigger(a,"hashchange")})},typeof g.init!="undefined"&&g.init()})(window)

$.fn.exists = function(){return this.length>0;}

function cmobile() {
    if (navigator.userAgent.indexOf('Android')!=-1 || navigator.userAgent.indexOf('iPhone')!=-1 || navigator.userAgent.indexOf('Nintendo 3DS')!=-1 || navigator.userAgent.indexOf('Nintendo DSi')!=-1 || window.innerWidth<=630) {
        return true;
    } else {
        return false;
    }
}

function screenCheck() {
    if (cmobile()){
        $(document.body).addClass('mobile');
        $(document.body).removeClass('nobile');
    } else if (window.innerWidth<=950){
        $(document.body).addClass('nobile');
        $(document.body).removeClass('mobile');
    } else  {
        $(document.body).removeClass('mobile');
        $(document.body).removeClass('nobile');
    }
}

$(document).ready(function() {
    var quote = quotes[Math.floor(Math.random()*quotes.length)];
    $('#quote').html(quote);

    if(navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false) {
        $('meta[name=viewport]').attr('content', 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />');
    }

    /* Topbar Menu */
    $('#toptitle').click(function() {
        if ($('body.menu').exists()) {
            $(document.body).removeClass('menu');
        } else {
            $(document.body).addClass('menu');
        }
    });
    $('#topbar').on("mouseleave", function(){
        if ($('body.menu').exists()) {
            $(document.body).removeClass('menu');
        }
    });
});

$(window).load(function() {
    screenCheck();
    $(window).resize(function() {
        screenCheck();
    });
});<|endoftext|>


<commit_before>/* Custom color plugin
 * by jd and panpawn
 */

var filepath = 'config/customcolors.json';
var customColors = {};
Gold.customColors = customColors;
var fs = require('fs');
var request = require('request');

function load () {
	fs.readFile(filepath, 'utf8', function (err, file) {
		if (err) return;
		customColors = JSON.parse(file);
	});
}
load();

function updateColor() {
	fs.writeFileSync(filepath, JSON.stringify(customColors));

	var newCss = '/* COLORS START */\n';

	for (var name in customColors) {
		newCss += generateCSS(name, customColors[name]);
	}
	newCss += '/* COLORS END */\n';

	var file = fs.readFileSync('config/custom.css', 'utf8').split('\n');
	if (~file.indexOf('/* COLORS START */')) file.splice(file.indexOf('/* COLORS START */'), (file.indexOf('/* COLORS END */') - file.indexOf('/* COLORS START */')) + 1);
	fs.writeFileSync('config/custom.css', file.join('\n') + newCss);
	request('http://play.pokemonshowdown.com/customcss.php?server=gold&invalidate', function callback(error, res, body) {
		if (error) return console.log('updateColor error: ' + error);
	});
}

function generateCSS(name, color) {
	var css = '';
	var rooms = [];
	name = toId(name);
	for (var room in Rooms.rooms) {
		if (Rooms.rooms[room].id === 'global' || Rooms.rooms[room].type !== 'chat' || Rooms.rooms[room].isPersonal) continue;
		rooms.push('#' + Rooms.rooms[room].id + '-userlist-user-' + name + ' strong em');
		rooms.push('#' + Rooms.rooms[room].id + '-userlist-user-' + name + ' strong');
		rooms.push('#' + Rooms.rooms[room].id + '-userlist-user-' + name + ' span');
	}
	css = rooms.join(', ');
	css += '{\ncolor: ' + color + ' !important;\n}\n';
	css += '.chat.chatmessage-' + name + ' strong {\n';
	css += 'color: ' + color + ' !important;\n}\n';
	return css;
}

exports.commands = {
	customcolour: 'customcolor',
	customcolor: function (target, room, user) {
		if (!this.can('pban')) return this.errorReply("Access denied.");
		target = target.split(',');
		for (var u in target) target[u] = target[u].trim();
		if (!target[1]) return this.parse('/help customcolor');
		if (toId(target[0]).length > 19) return this.errorReply("Usernames are not this long...");
		if (target[1] === 'delete') {
			if (!customColors[toId(target[0])]) return this.errorReply('/customcolor - ' + target[0] + ' does not have a custom color.');
			delete customColors[toId(target[0])];
			updateColor();
			this.sendReply("You removed " + target[0] + "'s custom color.");
			Rooms('staff').add(user.name + " removed " + target[0] + "'s custom color.").update();
			if (Users(target[0]) && Users(target[0]).connected) Users(target[0]).popup(user.name + " removed your custom color.");
			return;
		}

		this.sendReply("|raw|You have given " + Tools.escapeHTML(target[0]) + " a custom color.");
		Rooms('staff').add('|raw|' + Tools.escapeHTML(target[0]) + " has recieved a custom color</fon> from " + Tools.escapeHTML(user.name) + ".").update();
		customColors[toId(target[0])] = target[1];
		updateColor();
	},
	customcolorhelp: ["Commands Include:",
				"/customcolor [user], [hex] - Gives [user] a custom color of [hex]",
				"/customcolor [user], delete - Deletes a user's custom color"],
};<commit_msg>General customcolors updates<commit_after>/* Custom color plugin
 * by jd and panpawn
 */

var filepath = 'config/customcolors.json';
Gold.customColors = {};
var fs = require('fs');
var request = require('request');

function load () {
	fs.readFile(filepath, 'utf8', function (err, file) {
		if (err) return;
		Gold.customColors = JSON.parse(file);
	});
}
load();

function updateColor() {
	fs.writeFileSync(filepath, JSON.stringify(Gold.customColors));

	var newCss = '/* COLORS START */\n';

	for (var name in Gold.customColors) {
		newCss += generateCSS(name, Gold.customColors[name]);
	}
	newCss += '/* COLORS END */\n';

	var file = fs.readFileSync('config/custom.css', 'utf8').split('\n');
	if (~file.indexOf('/* COLORS START */')) file.splice(file.indexOf('/* COLORS START */'), (file.indexOf('/* COLORS END */') - file.indexOf('/* COLORS START */')) + 1);
	fs.writeFileSync('config/custom.css', file.join('\n') + newCss);
	request('http://play.pokemonshowdown.com/customcss.php?server=gold&invalidate', function callback(error, res, body) {
		if (error) return console.log('updateColor error: ' + error);
	});
}

function generateCSS(name, color) {
	var css = '';
	var rooms = [];
	name = toId(name);
	for (var room in Rooms.rooms) {
		if (Rooms.rooms[room].id === 'global' || Rooms.rooms[room].type !== 'chat' || Rooms.rooms[room].isPersonal) continue;
		rooms.push('#' + Rooms.rooms[room].id + '-userlist-user-' + name + ' strong em');
		rooms.push('#' + Rooms.rooms[room].id + '-userlist-user-' + name + ' strong');
		rooms.push('#' + Rooms.rooms[room].id + '-userlist-user-' + name + ' span');
	}
	css = rooms.join(', ');
	css += '{\ncolor: ' + color + ' !important;\n}\n';
	css += '.chat.chatmessage-' + name + ' strong {\n';
	css += 'color: ' + color + ' !important;\n}\n';
	return css;
}

exports.commands = {
	customcolour: 'customcolor',
	customcolor: function (target, room, user) {
		if (!this.can('pban')) return this.errorReply("Access denied.");
		target = target.split(',');
		for (var u in target) target[u] = target[u].trim();
		if (!target[1]) return this.parse('/help customcolor');
		if (toId(target[0]).length > 19) return this.errorReply("Usernames are not this long...");
		if (target[1] === 'delete') {
			if (!Gold.customColors[toId(target[0])]) return this.errorReply('/customcolor - ' + target[0] + ' does not have a custom color.');
			delete Gold.customColors[toId(target[0])];
			updateColor();
			this.sendReply("You removed " + target[0] + "'s custom color.");
			Rooms('staff').add(user.name + " removed " + target[0] + "'s custom color.").update();
			if (Users(target[0]) && Users(target[0]).connected) Users(target[0]).popup(user.name + " removed your custom color.");
			return;
		}

		this.sendReply("|raw|You have given " + Tools.escapeHTML(target[0]) + " a custom color.");
		Rooms('staff').add('|raw|' + Tools.escapeHTML(target[0]) + " has recieved a custom color</fon> from " + Tools.escapeHTML(user.name) + ".").update();
		Gold.customColors[toId(target[0])] = target[1];
		updateColor();
	},
	customcolorhelp: ["Commands Include:",
				"/customcolor [user], [hex] - Gives [user] a custom color of [hex]",
				"/customcolor [user], delete - Deletes a user's custom color"],
};<|endoftext|>


<commit_before>"use strict";

exports.commands = {
    rf: 'roomfounder',
	roomfounder: function (target, room, user) {
		if (!this.can('declare')) return false;
		if (!room.chatRoomData) return this.errorReply("/roomfounder - This room isn't designed for per-room moderation to be added.");
		target = this.splitTarget(target, true);
		let targetUser = this.targetUser;
		if (!targetUser) return this.errorReply("User '" + this.targetUsername + "' is not online.");
		if (room.isPersonal) return this.errorReply("You can't do this in personal rooms.");
		if (!room.auth) room.auth = room.chatRoomData.auth = {};
		let name = targetUser.name;
		room.auth[targetUser.userid] = '#';
		room.founder = targetUser.userid;
		this.addModCommand(name + ' was appointed to Room Founder by ' + user.name + '.');
		room.onUpdateIdentity(targetUser);
		room.chatRoomData.founder = room.founder;
		Rooms.global.writeChatRoomData();
	},

	roomdefounder: 'deroomfounder',
	deroomfounder: function (target, room, user) {
		if (!this.can('declare')) return false;
		if (!room.auth) return this.errorReply("/roomdeowner - This room isn't designed for per-room moderation");
		target = this.splitTarget(target, true);
		let targetUser = this.targetUser;
		let name = this.targetUsername;
		let userid = toId(name);
		if (room.isPersonal) return this.errorReply("You can't do this in personal rooms.");
		if (!userid || userid === '') return this.errorReply("User '" + name + "' does not exist.");
		if (room.founder !== userid) return this.errorReply("The specified user is not a roomowner.");
		delete room.auth[userid];
		delete room.founder;
		this.sendReply(name + ' was demoted from Room Founder by ' + user.name + '.');
		if (targetUser) targetUser.updateIdentity();
		if (room.chatRoomData) Rooms.global.writeChatRoomData();
	},
};<commit_msg>Setup: Room Founder<commit_after>"use strict";

exports.commands = {
		rf: 'roomfounder',
	roomfounder: function (target, room, user) {
		if (!room.chatRoomData) return this.sendReply("/roomfounder - This room isn't designed for per-room moderation to be added.");
		target = this.splitTarget(target, true);
		let targetUser = this.targetUser;
		if (!targetUser) return this.sendReply("User '" + this.targetUsername + "' is not online.");
		if (!this.can('declare')) return false;
		if (room.isPersonal) return this.sendReply("You can't do this in personal rooms.");
		if (!room.auth) room.auth = room.chatRoomData.auth = {};
		if (!room.leagueauth) room.leagueauth = room.chatRoomData.leagueauth = {};
		let name = targetUser.name;
		room.auth[targetUser.userid] = '#';
		room.founder = targetUser.userid;
		this.addModCommand(name + ' was appointed to Room Founder by ' + user.name + '.');
		room.onUpdateIdentity(targetUser);
		room.chatRoomData.founder = room.founder;
		Rooms.global.writeChatRoomData();
	},

	roomdefounder: 'deroomfounder',
	deroomfounder: function (target, room, user) {
		if (!room.auth) return this.sendReply("/roomdeowner - This room isn't designed for per-room moderation");
		target = this.splitTarget(target, true);
		let targetUser = this.targetUser;
		let name = this.targetUsername;
		let userid = toId(name);
		if (room.isPersonal) return this.sendReply("You can't do this in personal rooms.");
		if (!userid || userid === '') return this.sendReply("User '" + name + "' does not exist.");
		if (room.auth[userid] !== '#') return this.sendReply("User '" + name + "' is not a room founder.");
		if (!this.can('declare')) return false;
		delete room.auth[userid];
		delete room.founder;
		this.sendReply(name + ' was demoted from Room Founder by ' + user.name + '.');
		if (targetUser) targetUser.updateIdentity();
		if (room.chatRoomData) Rooms.global.writeChatRoomData();
	},
}
<|endoftext|>


<commit_before>var crypto = require('crypto');
var rpc = require('./rpc/rpc');
var controller = require('./webRtcController');
var ST = require('./Stream');
var io = require('socket.io').listen(8080);

io.set('log level', 1);

var nuveKey = 'claveNuve';

var WARNING_N_ROOMS = 15;
var LIMIT_N_ROOMS = 20;

var INTERVAL_TIME_KEEPALIVE = 1000;

var myId;
var myIP;
var rooms = {};
var myState;

/*
 * Sends a massege of type 'type' to all sockets in a determined room.
 */
var sendMsgToRoom = function(room, type, arg) {

    var sockets = room.sockets;
    for(var id in sockets) {
        console.log('Sending message to', sockets[id], 'in room ', room.id);
        io.sockets.socket(sockets[id]).emit(type, arg);
    }
};

var addToCloudHandler = function(callback) {

    var interfaces = require('os').networkInterfaces();
    var addresses = [];
    for (k in interfaces) {
        for (k2 in interfaces[k]) {
            var address = interfaces[k][k2];
            if (address.family == 'IPv4' && !address.internal) {
                addresses.push(address.address)
            }
        }
    }

    var myIP = addresses[0];

    rpc.callRpc('cloudHandler', 'addNewErizoController', myIP, function(id) {

        if(id == 'timeout') {
            console.log('CloudHandler does not respond');
            return;
        }

        myId = id;
        myState = 2;

        var intervarId = setInterval(function() {

            rpc.callRpc('cloudHandler', 'keepAlive', myId, function(result){
                if(result === 'whoareyou') {
                    console.log('I don`t exist in cloudHandler. I`m going to be killed');
                    clearInterval(intervarId);
                    rpc.callRpc('cloudHandler', 'killMe', myIP, function(){});
                }
            });

        }, INTERVAL_TIME_KEEPALIVE);

        callback();

    });
}

//*******************************************************************
//       Cuando añado o borro salas calculo con un algoritmo propio cuál es mi estado
//       Si cambio de estado envío mensaje a cloudHandler
//
//       States:
//            0: Not available
//            1: Warning
//            2: Available
//*******************************************************************
var updateMyState = function() {

    var nRooms = 0, newState;

    for(var i in rooms) {
        nRooms++;
    }

    if(nRooms < WARNING_N_ROOMS) newState = 2;
    else if(nRooms > LIMIT_N_ROOMS) newState = 0;
    else newState = 1;

    if(newState == myState) return;

    myState = newState;

    var info = {id: myId, state: myState};
    rpc.callRpc('cloudHandler', 'setInfo', info, function(){});
}

rpc.connect(function() {

    addToCloudHandler(function() {

        var rpcID = 'erizoController_' + myId;

        rpc.bind(rpcID, listen);

    });
});

var listen = function() {

    io.sockets.on('connection', function (socket) {

        console.log("Socket connect ", socket.id);

        // Gets 'token' messages on the socket. Checks the signature and ask nuve if it is valid.
        // Then registers it in the room and callback to the client.
        socket.on('token', function (token, callback) {

            var tokenDB;

            if(checkSignature(token, nuveKey)) {

                rpc.callRpc('nuve', 'deleteToken', token.tokenId, function(resp) {

                    if (resp == 'error') {
                        console.log('Token does not exist');
                        callback('error', 'Token does not exist');
                        socket.disconnect();

                    } else if (resp == 'timeout') {
                        console.log('Nuve does not respond');
                        callback('error', 'Nuve does not respond');
                        socket.disconnect();

                    } else if (token.host == resp.host) {
                        tokenDB = resp;
                        if(rooms[tokenDB.room] === undefined) {
                            var room = {};
                            room.id = tokenDB.room;
                            room.sockets = [];
                            room.sockets.push(socket.id);
                            room.streams = {}; //streamId: Stream
                            room.webRtcController = new controller.WebRtcController();
                            rooms[tokenDB.room] = room;
                            updateMyState();
                        } else {
                            rooms[tokenDB.room].sockets.push(socket.id);
                        }
                        var user = {name: tokenDB.userName, role: tokenDB.role};
                        socket.room = rooms[tokenDB.room];
                        socket.user = user;
                        socket.streams = []; //[list of streamIds]
                        socket.state = 'sleeping';
                        console.log('OK, Valid token');

                        var streamList = [];
                        for(var i in socket.room.streams) {
                            streamList.push(socket.room.streams[i].getPublicStream());
                        }

                        callback('success', {streams: streamList, id: socket.room.id});

                    } else {
                        console.log('Invalid host');
                        callback('error', 'Invalid host');
                        socket.disconnect();
                    }
                });

            } else {
                callback('error', 'Authentication error');
                socket.disconnect();
            }
        });

        //Gets 'ssendDataStream' messages on the socket in order to write a message in a dataStream.
        socket.on('sendDataStream', function(msg) {
            var sockets = socket.room.streams[msg.id].getDataSubscribers();
            for(var id in sockets) {
                console.log('Sending dataStream to', sockets[id], 'in stream ', msg.id, 'mensaje', msg.msg);
                io.sockets.socket(sockets[id]).emit('onDataStream', msg);
            }
        });

        //Gets 'publish' messages on the socket in order to add new stream to the room.
        socket.on('publish', function(options, sdp, callback) {

            if (options.state !== 'data') {
                if (options.state === 'offer' && socket.state === 'sleeping') {
                    var id = Math.random()*100000000000000000;
                    socket.room.webRtcController.addPublisher(id, sdp, function (answer) {
                        socket.state = 'waitingOk';
                        callback(answer, id);
                    });

                } else if (options.state === 'ok' && socket.state === 'waitingOk') {
                    var st = new ST.Stream({id: options.streamId, audio: options.audio, video: options.video, data: options.data, attributes: options.attributes});
                    socket.state = 'sleeping';
                    socket.streams.push(options.streamId);
                    socket.room.streams[options.streamId] = st;
                    sendMsgToRoom(socket.room, 'onAddStream', st.getPublicStream());
                }
            } else {
                var id = Math.random()*100000000000000000;
                var st = new ST.Stream({id: id, audio: options.audio, video: options.video, data: options.data, attributes: options.attributes});
                socket.streams.push(id);
                socket.room.streams[id] = st;
                callback(undefined, id);
                sendMsgToRoom(socket.room, 'onAddStream', st.getPublicStream());
            }

        });

        //Gets 'subscribe' messages on the socket in order to add new subscriber to a determined stream (options.streamId).
        socket.on('subscribe', function(options, sdp, callback) {

            if (socket.room.streams[options.streamId] === undefined) {
                return;
            }

            socket.room.streams[options.streamId].addDataSubscriber(socket.id);

            if(socket.room.streams[options.streamId].hasAudio() || socket.room.streams[options.streamId].hasVideo()) {
                socket.room.webRtcController.addSubscriber(socket.id, options.streamId, sdp, function (answer) {
                    callback(answer);
                });
            } else {
                callback(undefined);
            }

        });

        //Gets 'unpublish' messages on the socket in order to remove a stream from the room.
        socket.on('unpublish', function(streamId) {

            sendMsgToRoom(socket.room, 'onRemoveStream', {id: streamId});

            if(socket.room.streams[streamId].hasAudio() && socket.room.streams[streamId].hasVideo()) {
                socket.state = 'sleeping';
                socket.room.webRtcController.removePublisher(streamId);
            }

            for(var i in socket.room.streams) {
                socket.room.streams[i].removeDataSubscriber(socket.id);
            }

            var index = socket.streams.indexOf(streamId);
            if(index !== -1) {
                socket.streams.splice(index, 1);
            }
            if (socket.room.streams[streamId]) {
                delete socket.room.streams[streamId];
            }

        });

        //Gets 'unsubscribe' messages on the socket in order to remove a subscriber from a determined stream (to).
        socket.on('unsubscribe', function(to) {

            if (socket.room.streams[to] === undefined) {
                return;
            }

            socket.room.streams[to].removeDataSubscriber(socket.id);

            if (socket.room.streams[to].audio && socket.room.streams[to].video) {
                socket.room.webRtcController.removeSubscriber(socket.id, to);
            }

        });

        //When a client leaves the room erizoController removes its streams from the room if exists.
        socket.on('disconnect', function () {

            console.log('Socket disconnect ', socket.id);

            for(var i in socket.streams) {
                sendMsgToRoom(socket.room, 'onRemoveStream', {id: socket.streams[i]});
            }

            if(socket.room !== undefined) {

                for(var i in socket.room.streams) {
                    socket.room.streams[i].removeDataSubscriber(socket.id);
                }

                var index = socket.room.sockets.indexOf(socket.id);
                if(index !== -1) {
                    socket.room.sockets.splice(index, 1);
                }
                for(var i in socket.streams) {
                    var id = socket.streams[i];

                    if (socket.room.streams[id].hasAudio() && socket.room.streams[id].hasVideo()) {
                        socket.room.webRtcController.removeClient(socket.id, id);
                    };

                    if (socket.room.streams[id]) {
                        delete socket.room.streams[id];
                    }
                }
            }

            if (socket.room.sockets.length == 0) {
                console.log('Empty room ' , socket.room.id, '. Deleting it');
                delete rooms[socket.room.id];
                updateMyState();
            };
        });
    });
}

/*
 *Gets a list of users in a determined room.
 */
exports.getUsersInRoom = function(room, callback) {

    var users = [];
    if(rooms[room] === undefined) {
        callback(users);
        return;
    }

    var sockets = rooms[room].sockets;

    for(var id in sockets) {
        users.push(io.sockets.socket(sockets[id]).user);
    }

    callback(users);
}

/*
 * Delete a determined room.
 */
exports.deleteRoom = function(room, callback) {
    if(rooms[room] === undefined) {
        callback('Success');
        return;
    }
    var sockets = rooms[room].sockets;

    for(var id in sockets) {
        rooms[room].webRtcController.removeClient(sockets[id]);
    }
    console.log('Deleting room ', room, rooms);
    delete rooms[room];
    updateMyState();
    console.log('1 Deleting room ', room, rooms);
    callback('Success');
}

var checkSignature = function(token, key) {

    var calculatedSignature = calculateSignature(token, key);

    if(calculatedSignature != token.signature) {
        console.log('Auth fail. Invalid signature.');
        return false;
    } else {
        return true;
    }
}

var calculateSignature = function(token, key) {

    var toSign = token.tokenId + ',' + token.host;
    var signed = crypto.createHmac('sha1', key).update(toSign).digest('hex');
    return (new Buffer(signed)).toString('base64');
}

<commit_msg>Fixed a bug in subscribe method<commit_after>var crypto = require('crypto');
var rpc = require('./rpc/rpc');
var controller = require('./webRtcController');
var ST = require('./Stream');
var io = require('socket.io').listen(8080);

io.set('log level', 1);

var nuveKey = 'claveNuve';

var WARNING_N_ROOMS = 15;
var LIMIT_N_ROOMS = 20;

var INTERVAL_TIME_KEEPALIVE = 1000;

var myId;
var myIP;
var rooms = {};
var myState;

/*
 * Sends a massege of type 'type' to all sockets in a determined room.
 */
var sendMsgToRoom = function(room, type, arg) {

    var sockets = room.sockets;
    for(var id in sockets) {
        console.log('Sending message to', sockets[id], 'in room ', room.id);
        io.sockets.socket(sockets[id]).emit(type, arg);
    }
};

var addToCloudHandler = function(callback) {

    var interfaces = require('os').networkInterfaces();
    var addresses = [];
    for (k in interfaces) {
        for (k2 in interfaces[k]) {
            var address = interfaces[k][k2];
            if (address.family == 'IPv4' && !address.internal) {
                addresses.push(address.address)
            }
        }
    }

    var myIP = addresses[0];

    rpc.callRpc('cloudHandler', 'addNewErizoController', myIP, function(id) {

        if(id == 'timeout') {
            console.log('CloudHandler does not respond');
            return;
        }

        myId = id;
        myState = 2;

        var intervarId = setInterval(function() {

            rpc.callRpc('cloudHandler', 'keepAlive', myId, function(result){
                if(result === 'whoareyou') {
                    console.log('I don`t exist in cloudHandler. I`m going to be killed');
                    clearInterval(intervarId);
                    rpc.callRpc('cloudHandler', 'killMe', myIP, function(){});
                }
            });

        }, INTERVAL_TIME_KEEPALIVE);

        callback();

    });
}

//*******************************************************************
//       Cuando añado o borro salas calculo con un algoritmo propio cuál es mi estado
//       Si cambio de estado envío mensaje a cloudHandler
//
//       States:
//            0: Not available
//            1: Warning
//            2: Available
//*******************************************************************
var updateMyState = function() {

    var nRooms = 0, newState;

    for(var i in rooms) {
        nRooms++;
    }

    if(nRooms < WARNING_N_ROOMS) newState = 2;
    else if(nRooms > LIMIT_N_ROOMS) newState = 0;
    else newState = 1;

    if(newState == myState) return;

    myState = newState;

    var info = {id: myId, state: myState};
    rpc.callRpc('cloudHandler', 'setInfo', info, function(){});
}

rpc.connect(function() {

    addToCloudHandler(function() {

        var rpcID = 'erizoController_' + myId;

        rpc.bind(rpcID, listen);

    });
});

var listen = function() {

    io.sockets.on('connection', function (socket) {

        console.log("Socket connect ", socket.id);

        // Gets 'token' messages on the socket. Checks the signature and ask nuve if it is valid.
        // Then registers it in the room and callback to the client.
        socket.on('token', function (token, callback) {

            var tokenDB;

            if(checkSignature(token, nuveKey)) {

                rpc.callRpc('nuve', 'deleteToken', token.tokenId, function(resp) {

                    if (resp == 'error') {
                        console.log('Token does not exist');
                        callback('error', 'Token does not exist');
                        socket.disconnect();

                    } else if (resp == 'timeout') {
                        console.log('Nuve does not respond');
                        callback('error', 'Nuve does not respond');
                        socket.disconnect();

                    } else if (token.host == resp.host) {
                        tokenDB = resp;
                        if(rooms[tokenDB.room] === undefined) {
                            var room = {};
                            room.id = tokenDB.room;
                            room.sockets = [];
                            room.sockets.push(socket.id);
                            room.streams = {}; //streamId: Stream
                            room.webRtcController = new controller.WebRtcController();
                            rooms[tokenDB.room] = room;
                            updateMyState();
                        } else {
                            rooms[tokenDB.room].sockets.push(socket.id);
                        }
                        var user = {name: tokenDB.userName, role: tokenDB.role};
                        socket.room = rooms[tokenDB.room];
                        socket.user = user;
                        socket.streams = []; //[list of streamIds]
                        socket.state = 'sleeping';
                        console.log('OK, Valid token');

                        var streamList = [];
                        for(var i in socket.room.streams) {
                            streamList.push(socket.room.streams[i].getPublicStream());
                        }

                        callback('success', {streams: streamList, id: socket.room.id});

                    } else {
                        console.log('Invalid host');
                        callback('error', 'Invalid host');
                        socket.disconnect();
                    }
                });

            } else {
                callback('error', 'Authentication error');
                socket.disconnect();
            }
        });

        //Gets 'ssendDataStream' messages on the socket in order to write a message in a dataStream.
        socket.on('sendDataStream', function(msg) {
            var sockets = socket.room.streams[msg.id].getDataSubscribers();
            for(var id in sockets) {
                console.log('Sending dataStream to', sockets[id], 'in stream ', msg.id, 'mensaje', msg.msg);
                io.sockets.socket(sockets[id]).emit('onDataStream', msg);
            }
        });

        //Gets 'publish' messages on the socket in order to add new stream to the room.
        socket.on('publish', function(options, sdp, callback) {

            if (options.state !== 'data') {
                if (options.state === 'offer' && socket.state === 'sleeping') {
                    var id = Math.random()*100000000000000000;
                    socket.room.webRtcController.addPublisher(id, sdp, function (answer) {
                        socket.state = 'waitingOk';
                        callback(answer, id);
                    });

                } else if (options.state === 'ok' && socket.state === 'waitingOk') {
                    var st = new ST.Stream({id: options.streamId, audio: options.audio, video: options.video, data: options.data, attributes: options.attributes});
                    socket.state = 'sleeping';
                    socket.streams.push(options.streamId);
                    socket.room.streams[options.streamId] = st;
                    sendMsgToRoom(socket.room, 'onAddStream', st.getPublicStream());
                }
            } else {
                var id = Math.random()*100000000000000000;
                var st = new ST.Stream({id: id, audio: options.audio, video: options.video, data: options.data, attributes: options.attributes});
                socket.streams.push(id);
                socket.room.streams[id] = st;
                callback(undefined, id);
                sendMsgToRoom(socket.room, 'onAddStream', st.getPublicStream());
            }

        });

        //Gets 'subscribe' messages on the socket in order to add new subscriber to a determined stream (options.streamId).
        socket.on('subscribe', function(options, sdp, callback) {

            if (socket.room.streams[options.streamId] === undefined) {
                return;
            }

            socket.room.streams[options.streamId].addDataSubscriber(socket.id);

            if(socket.room.streams[options.streamId].hasAudio() || socket.room.streams[options.streamId].hasVideo()) {
                socket.room.webRtcController.addSubscriber(socket.id, options.streamId, sdp, function (answer) {
                    callback(answer);
                });
            } else {
                callback(undefined);
            }

        });

        //Gets 'unpublish' messages on the socket in order to remove a stream from the room.
        socket.on('unpublish', function(streamId) {

            sendMsgToRoom(socket.room, 'onRemoveStream', {id: streamId});

            if(socket.room.streams[streamId].hasAudio() || socket.room.streams[streamId].hasVideo()) {
                socket.state = 'sleeping';
                socket.room.webRtcController.removePublisher(streamId);
            }

            for(var i in socket.room.streams) {
                socket.room.streams[i].removeDataSubscriber(socket.id);
            }

            var index = socket.streams.indexOf(streamId);
            if(index !== -1) {
                socket.streams.splice(index, 1);
            }
            if (socket.room.streams[streamId]) {
                delete socket.room.streams[streamId];
            }

        });

        //Gets 'unsubscribe' messages on the socket in order to remove a subscriber from a determined stream (to).
        socket.on('unsubscribe', function(to) {

            if (socket.room.streams[to] === undefined) {
                return;
            }

            socket.room.streams[to].removeDataSubscriber(socket.id);

            if (socket.room.streams[to].audio || socket.room.streams[to].video) {
                socket.room.webRtcController.removeSubscriber(socket.id, to);
            }

        });

        //When a client leaves the room erizoController removes its streams from the room if exists.
        socket.on('disconnect', function () {

            console.log('Socket disconnect ', socket.id);

            for(var i in socket.streams) {
                sendMsgToRoom(socket.room, 'onRemoveStream', {id: socket.streams[i]});
            }

            if(socket.room !== undefined) {

                for(var i in socket.room.streams) {
                    socket.room.streams[i].removeDataSubscriber(socket.id);
                }

                var index = socket.room.sockets.indexOf(socket.id);
                if(index !== -1) {
                    socket.room.sockets.splice(index, 1);
                }
                for(var i in socket.streams) {
                    var id = socket.streams[i];

                    if (socket.room.streams[id].hasAudio() || socket.room.streams[id].hasVideo()) {
                        socket.room.webRtcController.removeClient(socket.id, id);
                    };

                    if (socket.room.streams[id]) {
                        delete socket.room.streams[id];
                    }
                }
            }

            if (socket.room.sockets.length == 0) {
                console.log('Empty room ' , socket.room.id, '. Deleting it');
                delete rooms[socket.room.id];
                updateMyState();
            };
        });
    });
}

/*
 *Gets a list of users in a determined room.
 */
exports.getUsersInRoom = function(room, callback) {

    var users = [];
    if(rooms[room] === undefined) {
        callback(users);
        return;
    }

    var sockets = rooms[room].sockets;

    for(var id in sockets) {
        users.push(io.sockets.socket(sockets[id]).user);
    }

    callback(users);
}

/*
 * Delete a determined room.
 */
exports.deleteRoom = function(room, callback) {
    if(rooms[room] === undefined) {
        callback('Success');
        return;
    }
    var sockets = rooms[room].sockets;

    for(var id in sockets) {
        rooms[room].webRtcController.removeClient(sockets[id]);
    }
    console.log('Deleting room ', room, rooms);
    delete rooms[room];
    updateMyState();
    console.log('1 Deleting room ', room, rooms);
    callback('Success');
}

var checkSignature = function(token, key) {

    var calculatedSignature = calculateSignature(token, key);

    if(calculatedSignature != token.signature) {
        console.log('Auth fail. Invalid signature.');
        return false;
    } else {
        return true;
    }
}

var calculateSignature = function(token, key) {

    var toSign = token.tokenId + ',' + token.host;
    var signed = crypto.createHmac('sha1', key).update(toSign).digest('hex');
    return (new Buffer(signed)).toString('base64');
}

<|endoftext|>