<commit_before>/* global URL, Blob */

var airplay = require('airplay-js')
var chromecasts = require('chromecasts')()
var dragDrop = require('drag-drop')
var electron = require('electron')
var networkAddress = require('network-address')
var path = require('path')
var throttle = require('throttleit')
var torrentPoster = require('./lib/torrent-poster')
var getClient = require('./lib/get-client')

var createElement = require('virtual-dom/create-element')
var diff = require('virtual-dom/diff')
var patch = require('virtual-dom/patch')

var HEADER_HEIGHT = 38

var App = require('./views/app')

var state = global.state = {
  server: null,
  player: null,
  currentPage: {
    type: 'list'
  },
  view: {
    title: 'WebTorrent',
    client: null,
    savedWindowBounds: null,
    history: [],
    historyIndex: 0,
    chromecast: null,
    airplay: null
  }
}

var currentVDom, rootElement, updateThrottled

function init () {
  currentVDom = App(state, dispatch)
  rootElement = createElement(currentVDom)
  document.body.appendChild(rootElement)

  updateThrottled = throttle(update, 250)

  getClient(function (err, client) {
    if (err) return onError(err)
    global.client = client
    state.view.client = client
    client.on('warning', onWarning)
    client.on('error', onError)
  })

  dragDrop('body', onFiles)

  chromecasts.on('update', function (player) {
    state.view.chromecast = player
    update()
  })

  airplay.createBrowser().on('deviceOn', function (player) {
    state.view.airplay = player
  }).start()

  document.addEventListener('paste', function () {
    electron.ipcRenderer.send('addTorrentFromPaste')
  })
}
init()

function update () {
  var newVDom = App(state, dispatch)
  var patches = diff(currentVDom, newVDom)
  rootElement = patch(rootElement, patches)
  currentVDom = newVDom
}

setInterval(function () {
  update()
}, 5000)

function dispatch (action, ...args) {
  console.log('dispatch: %s %o', action, args)
  if (action === 'addTorrent') {
    addTorrent(args[0] /* torrentId */)
  }
  if (action === 'seed') {
    seed(args[0] /* files */)
  }
  if (action === 'openPlayer') {
    openPlayer(args[0] /* torrent */)
  }
  // if (action === 'closePlayer') {
  //   closePlayer()
  // }
  if (action === 'openChromecast') {
    openChromecast(args[0] /* torrent */)
  }
  if (action === 'openAirplay') {
    openAirplay(args[0] /* torrent */)
  }
  if (action === 'setDimensions') {
    setDimensions(args[0] /* dimensions */)
  }
  if (action === 'back') {
    if (state.player === 'local') {
      restoreBounds()
      closePlayer()
    }
  }
}

electron.ipcRenderer.on('addTorrent', function (e, torrentId) {
  addTorrent(torrentId)
})

electron.ipcRenderer.on('seed', function (e, files) {
  seed(files)
})

function onFiles (files) {
  // .torrent file = start downloading the torrent
  files.filter(isTorrentFile).forEach(function (torrentFile) {
    dispatch('addTorrent', torrentFile)
  })

  // everything else = seed these files
  dispatch('seed', files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
  var extname = path.extname(file.name).toLowerCase()
  return extname === '.torrent'
}

function isNotTorrentFile (file) {
  return !isTorrentFile(file)
}

function addTorrent (torrentId) {
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.add(torrentId)
    addTorrentEvents(torrent)
  })
}

function seed (files) {
  if (files.length === 0) return

  // Seed from WebTorrent
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.seed(files)
    addTorrentEvents(torrent)
  })
}

function addTorrentEvents (torrent) {
  torrent.on('infoHash', update)
  torrent.on('done', update)
  torrent.on('download', updateThrottled)
  torrent.on('upload', updateThrottled)
  torrent.on('ready', function () {
    torrentReady(torrent)
  })
  update()
}

function torrentReady (torrent) {
  torrentPoster(torrent, function (err, buf) {
    if (err) return onError(err)
    torrent.posterURL = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' }))
    update()
  })
  update()
}

function startServer (torrent, cb) {
  // use largest file
  var index = torrent.files.indexOf(torrent.files.reduce(function (a, b) {
    return a.length > b.length ? a : b
  }))

  var server = torrent.createServer()
  server.listen(0, function () {
    var port = server.address().port
    var urlSuffix = ':' + port + '/' + index
    state.server = {
      server: server,
      localURL: 'http://localhost' + urlSuffix,
      networkURL: 'http://' + networkAddress() + urlSuffix
    }
    cb()
  })
}

function closeServer () {
  state.server.server.destroy()
  state.server = null
}

function openPlayer (torrent) {
  startServer(torrent, function () {
    state.player = 'local'
    update()
  })
}

function closePlayer () {
  closeServer()
  state.player = null
  update()
}

function openChromecast (torrent) {
  startServer(torrent, function () {
    state.view.chromecast.play(state.server.networkURL, { title: 'WebTorrent — ' + torrent.name })
    state.view.chromecast.on('error', function (err) {
      err.message = 'Chromecast: ' + err.message
      onError(err)
    })
    state.player = 'chromecast'
    update()
  })
}

function openAirplay (torrent) {
  startServer(torrent, function () {
    state.view.airplay.play(state.server.networkURL, 0, function () {})
    // TODO: handle airplay errors
    state.player = 'airplay'
    update()
  })
}

function setDimensions (dimensions) {
  state.view.savedWindowBounds = electron.remote.getCurrentWindow().getBounds()

  // Limit window size to screen size
  var workAreaSize = electron.remote.screen.getPrimaryDisplay().workAreaSize
  var width = Math.min(dimensions.width, workAreaSize.width)
  var height = Math.min(dimensions.height, workAreaSize.height)
  var aspectRatio = width / height

  // add header height
  height += HEADER_HEIGHT

  // Center window on screen
  var x = Math.floor((workAreaSize.width - width) / 2)
  var y = Math.floor((workAreaSize.height - height) / 2)

  electron.ipcRenderer.send('setAspectRatio', aspectRatio, { width: 0, height: HEADER_HEIGHT })
  electron.ipcRenderer.send('setBounds', { x, y, width, height })
}

function restoreBounds () {
  electron.ipcRenderer.send('setAspectRatio', 0)
  electron.ipcRenderer.send('setBounds', state.view.savedWindowBounds, true)
}

function onError (err) {
  console.error(err.stack)
  window.alert(err.message || err)
  update()
}

function onWarning (err) {
  console.log('warning: %s', err.message)
}
<commit_msg>remove redundant comments<commit_after>/* global URL, Blob */

var airplay = require('airplay-js')
var chromecasts = require('chromecasts')()
var dragDrop = require('drag-drop')
var electron = require('electron')
var networkAddress = require('network-address')
var path = require('path')
var throttle = require('throttleit')
var torrentPoster = require('./lib/torrent-poster')
var getClient = require('./lib/get-client')

var createElement = require('virtual-dom/create-element')
var diff = require('virtual-dom/diff')
var patch = require('virtual-dom/patch')

var HEADER_HEIGHT = 38

var App = require('./views/app')

var state = global.state = {
  server: null,
  player: null,
  currentPage: {
    type: 'list'
  },
  view: {
    title: 'WebTorrent',
    client: null,
    savedWindowBounds: null,
    history: [],
    historyIndex: 0,
    chromecast: null,
    airplay: null
  }
}

var currentVDom, rootElement, updateThrottled

function init () {
  currentVDom = App(state, dispatch)
  rootElement = createElement(currentVDom)
  document.body.appendChild(rootElement)

  updateThrottled = throttle(update, 250)

  getClient(function (err, client) {
    if (err) return onError(err)
    global.client = client
    state.view.client = client
    client.on('warning', onWarning)
    client.on('error', onError)
  })

  dragDrop('body', onFiles)

  chromecasts.on('update', function (player) {
    state.view.chromecast = player
    update()
  })

  airplay.createBrowser().on('deviceOn', function (player) {
    state.view.airplay = player
  }).start()

  document.addEventListener('paste', function () {
    electron.ipcRenderer.send('addTorrentFromPaste')
  })
}
init()

function update () {
  var newVDom = App(state, dispatch)
  var patches = diff(currentVDom, newVDom)
  rootElement = patch(rootElement, patches)
  currentVDom = newVDom
}

setInterval(function () {
  update()
}, 5000)

function dispatch (action, ...args) {
  console.log('dispatch: %s %o', action, args)
  if (action === 'addTorrent') {
    addTorrent(args[0] /* torrentId */)
  }
  if (action === 'seed') {
    seed(args[0] /* files */)
  }
  if (action === 'openPlayer') {
    openPlayer(args[0] /* torrent */)
  }
  // if (action === 'closePlayer') {
  //   closePlayer()
  // }
  if (action === 'openChromecast') {
    openChromecast(args[0] /* torrent */)
  }
  if (action === 'openAirplay') {
    openAirplay(args[0] /* torrent */)
  }
  if (action === 'setDimensions') {
    setDimensions(args[0] /* dimensions */)
  }
  if (action === 'back') {
    if (state.player === 'local') {
      restoreBounds()
      closePlayer()
    }
  }
}

electron.ipcRenderer.on('addTorrent', function (e, torrentId) {
  addTorrent(torrentId)
})

electron.ipcRenderer.on('seed', function (e, files) {
  seed(files)
})

function onFiles (files) {
  // .torrent file = start downloading the torrent
  files.filter(isTorrentFile).forEach(function (torrentFile) {
    dispatch('addTorrent', torrentFile)
  })

  // everything else = seed these files
  dispatch('seed', files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
  var extname = path.extname(file.name).toLowerCase()
  return extname === '.torrent'
}

function isNotTorrentFile (file) {
  return !isTorrentFile(file)
}

function addTorrent (torrentId) {
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.add(torrentId)
    addTorrentEvents(torrent)
  })
}

function seed (files) {
  if (files.length === 0) return
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.seed(files)
    addTorrentEvents(torrent)
  })
}

function addTorrentEvents (torrent) {
  torrent.on('infoHash', update)
  torrent.on('done', update)
  torrent.on('download', updateThrottled)
  torrent.on('upload', updateThrottled)
  torrent.on('ready', function () {
    torrentReady(torrent)
  })
  update()
}

function torrentReady (torrent) {
  torrentPoster(torrent, function (err, buf) {
    if (err) return onError(err)
    torrent.posterURL = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' }))
    update()
  })
  update()
}

function startServer (torrent, cb) {
  // use largest file
  var index = torrent.files.indexOf(torrent.files.reduce(function (a, b) {
    return a.length > b.length ? a : b
  }))

  var server = torrent.createServer()
  server.listen(0, function () {
    var port = server.address().port
    var urlSuffix = ':' + port + '/' + index
    state.server = {
      server: server,
      localURL: 'http://localhost' + urlSuffix,
      networkURL: 'http://' + networkAddress() + urlSuffix
    }
    cb()
  })
}

function closeServer () {
  state.server.server.destroy()
  state.server = null
}

function openPlayer (torrent) {
  startServer(torrent, function () {
    state.player = 'local'
    update()
  })
}

function closePlayer () {
  closeServer()
  state.player = null
  update()
}

function openChromecast (torrent) {
  startServer(torrent, function () {
    state.view.chromecast.play(state.server.networkURL, { title: 'WebTorrent — ' + torrent.name })
    state.view.chromecast.on('error', function (err) {
      err.message = 'Chromecast: ' + err.message
      onError(err)
    })
    state.player = 'chromecast'
    update()
  })
}

function openAirplay (torrent) {
  startServer(torrent, function () {
    state.view.airplay.play(state.server.networkURL, 0, function () {})
    // TODO: handle airplay errors
    state.player = 'airplay'
    update()
  })
}

function setDimensions (dimensions) {
  state.view.savedWindowBounds = electron.remote.getCurrentWindow().getBounds()

  // Limit window size to screen size
  var workAreaSize = electron.remote.screen.getPrimaryDisplay().workAreaSize
  var width = Math.min(dimensions.width, workAreaSize.width)
  var height = Math.min(dimensions.height, workAreaSize.height)
  var aspectRatio = width / height

  height += HEADER_HEIGHT

  // Center window on screen
  var x = Math.floor((workAreaSize.width - width) / 2)
  var y = Math.floor((workAreaSize.height - height) / 2)

  electron.ipcRenderer.send('setAspectRatio', aspectRatio, { width: 0, height: HEADER_HEIGHT })
  electron.ipcRenderer.send('setBounds', { x, y, width, height })
}

function restoreBounds () {
  electron.ipcRenderer.send('setAspectRatio', 0)
  electron.ipcRenderer.send('setBounds', state.view.savedWindowBounds, true)
}

function onError (err) {
  console.error(err.stack)
  window.alert(err.message || err)
  update()
}

function onWarning (err) {
  console.log('warning: %s', err.message)
}
<|endoftext|>


<commit_before>var body = document.body;
var html = document.documentElement;
var body = html.getElementsByTagName("body")[0];
var table = body.getElementsByTagName("table")[0];
var size = 20; // Size of cell

// Credit to http://stackoverflow.com/questions/1145850/how-to-get-height-of-entire-document-with-javascript
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
var width = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth);
width -= 10; // Make the table a little smaller so there's a valid border.
height -= 10;
width = Math.floor(width/size);
height = Math.floor(height/size);
console.log("Width: "+width, " Height: "+height);
table.setAttribute("height", height*size + "px");
table.setAttribute("width", width*size + "px");
for (var i=0; i<height; i+=1) {
  var row = table.insertRow(i);
  for (var j=0; j<width; j+=1) {
  	var cell = row.insertCell(j);
  	cell.setAttribute("class", "emptycell");
  	cell.setAttribute("name", i+"_"+j);
    var btn = document.createElement("button");
    btn.setAttribute("class", "invisible");
  	btn.setAttribute("onclick", "placeFood("+i+","+j+")");
  	cell.appendChild(btn);
  }
}

function updateBoard(snake) {
  for (var i=0, cell; cell=table.cells[i]; i++) {
    console.log(cell);
	  var isSnakeCell = false;
	  for (var s in snake) {
  	  if (cell.name == s[0]+"_"+s[1]) {
    	  isSnakeCell = true;
    	  break;
    	}
	  }
	  if (isSnakeCell) {
      cell.setAttribute("class", "snakecell");
	  } else {
  	  cell.setAttribute("class", "emptycell");
  	}
	}
}<commit_msg>idk how to iterate<commit_after>var body = document.body;
var html = document.documentElement;
var body = html.getElementsByTagName("body")[0];
var table = body.getElementsByTagName("table")[0];
var size = 20; // Size of cell

// Credit to http://stackoverflow.com/questions/1145850/how-to-get-height-of-entire-document-with-javascript
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
var width = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth);
width -= 10; // Make the table a little smaller so there's a valid border.
height -= 10;
width = Math.floor(width/size);
height = Math.floor(height/size);
console.log("Width: "+width, " Height: "+height);
table.setAttribute("height", height*size + "px");
table.setAttribute("width", width*size + "px");
for (var i=0; i<height; i+=1) {
  var row = table.insertRow(i);
  for (var j=0; j<width; j+=1) {
  	var cell = row.insertCell(j);
  	cell.setAttribute("class", "emptycell");
  	cell.setAttribute("name", i+"_"+j);
    var btn = document.createElement("button");
    btn.setAttribute("class", "invisible");
  	btn.setAttribute("onclick", "placeFood("+i+","+j+")");
  	cell.appendChild(btn);
  }
}

function updateBoard(snake) {
	for (var r=0, row; r<table.rows.length; r++) {
	  for (var c=0; c<table.rows[r].cells.length; c++) {
  	  // console.log(table.rows[r].cells);
  	  // console.log(table.rows[r].cells[c]);
  	  var cell = table.rows[r].cells[c];
  	  console.log(cell.innerHTML);
	    var isSnakeCell = false;
	    for (var s in snake) {
  	    if (cell.name == s[0]+"_"+s[1]) {
    	    isSnakeCell = true;
    	    break;
    	  }
	    }
	    if (isSnakeCell) {
        cell.setAttribute("class", "snakecell");
	    } else {
  	    cell.setAttribute("class", "emptycell");
  	  }
	  }
	}
}<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Simen Brekken @simenbrekken
*/
var DefinePlugin = require("./DefinePlugin");

function EnvironmentPlugin(keys) {
	this.keys = Array.isArray(keys) ? keys : Array.prototype.slice.call(arguments);
}
module.exports = EnvironmentPlugin;

EnvironmentPlugin.prototype.apply = function(compiler) {
	compiler.apply(new DefinePlugin(this.keys.reduce(function(definitions, key) {
		var value = process.env[key];

		if(value === undefined) {
			compiler.plugin("this-compilation", function(compilation) {
				var error = new Error(key + " environment variable is undefined.");
				error.name = "EnvVariableNotDefinedError";
				compilation.warnings.push(error);
			});
		}

		definitions["process.env." + key] = value ? JSON.stringify(value) : "undefined";

		return definitions;
	}, {})));
};
<commit_msg>refactor(es6): refactor EnvironmentPlugin to ES6 class<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Simen Brekken @simenbrekken
*/

"use strict";

const DefinePlugin = require("./DefinePlugin");

class EnvironmentPlugin {
	constructor(keys) {
		this.keys = Array.isArray(keys) ? keys : Array.prototype.slice.call(arguments);
	}

	apply(compiler) {
		compiler.apply(new DefinePlugin(this.keys.reduce((definitions, key) => {
			const value = process.env[key];

			if(value === undefined) {
				compiler.plugin("this-compilation", (compilation) => {
					const error = new Error(key + " environment variable is undefined.");
					error.name = "EnvVariableNotDefinedError";
					compilation.warnings.push(error);
				});
			}

			definitions["process.env." + key] = value ? JSON.stringify(value) : "undefined";

			return definitions;
		}, {})));
	}
}

module.exports = EnvironmentPlugin;
<|endoftext|>


<commit_before>export const NodeTypes = {
  FRAGMENT: "FRAGMENT",
  P: "P",
  H1: "H1",
  H2: "H2",
  H3: "H3",
  H4: "H4",
  H5: "H5",
  H6: "H6",
  LINK: "LINK"
};

function parsePortableTextNodeType(portableTextNode) {
  if (portableTextNode._type === "block") {
    if (portableTextNode.style === "h1") {
      return NodeTypes.H1;
    }

    return NodeTypes.P;
  }

  return NodeTypes.FRAGMENT;
}

function parsePortableTextNodeAttrs(portableTextNode) {
  let nodeType = parsePortableTextNodeType(portableTextNode);

  let attrs = {};
  if (nodeType === NodeTypes.FRAGMENT) {
    attrs.text = portableTextNode.text;
  }

  if (portableTextNode.marks && portableTextNode.marks.length > 0) {
    nodeType = NodeTypes.LINK;
    attrs.href = "http://google.com";
  }

  return { type: nodeType, ...attrs };
}

export function parsePortableText(portableTextNode) {
  if (Array.isArray(portableTextNode)) {
    return portableTextNode.map(parsePortableText);
  }

  if (portableTextNode.children) {
    return {
      ...parsePortableTextNodeAttrs(portableTextNode),
      children: parsePortableText(portableTextNode.children)
    };
  }

  return parsePortableTextNodeAttrs(portableTextNode);
}
<commit_msg>Add image node handler<commit_after>export const NodeTypes = {
  FRAGMENT: "FRAGMENT",
  P: "P",
  H1: "H1",
  H2: "H2",
  H3: "H3",
  H4: "H4",
  H5: "H5",
  H6: "H6",
  LINK: "LINK",
  IMAGE: "IMAGE"
};

function parsePortableTextNodeType(portableTextNode) {
  if (portableTextNode._type === "block") {
    if (portableTextNode.style === "h1") {
      return NodeTypes.H1;
    }

    return NodeTypes.P;
  }

  if (portableTextNode._type === "mainImage") {
    return NodeTypes.IMAGE;
  }

  return NodeTypes.FRAGMENT;
}

function parsePortableTextNodeAttrs(portableTextNode) {
  let nodeType = parsePortableTextNodeType(portableTextNode);

  let attrs = {};
  if (nodeType === NodeTypes.FRAGMENT) {
    attrs.text = portableTextNode.text;
  }

  if (portableTextNode.marks && portableTextNode.marks.length > 0) {
    nodeType = NodeTypes.LINK;
    attrs.href = "http://google.com";
  }

  if (nodeType === NodeTypes.IMAGE) {
    attrs.alt = portableTextNode.alt;
    attrs.asset = portableTextNode.asset;
    attrs.caption = portableTextNode.caption;
  }

  return { type: nodeType, ...attrs };
}

export function parsePortableText(portableTextNode) {
  if (Array.isArray(portableTextNode)) {
    return portableTextNode.map(parsePortableText);
  }

  if (portableTextNode.children) {
    return {
      ...parsePortableTextNodeAttrs(portableTextNode),
      children: parsePortableText(portableTextNode.children)
    };
  }

  return parsePortableTextNodeAttrs(portableTextNode);
}
<|endoftext|>


<commit_before>let ArraySet = require('./ArraySet');

class DFANode {
	constructor(nfa_node_set, id) {
		this.nfa_node_set = nfa_node_set;
		this.id = id;
		this.transitions = {};
		this.acceptState = -1;
	}

	getTransition(ch) {
		return (this.transitions.hasOwnProperty(ch)) ? this.transitions[ch] : null;
	}

	setTransition(ch, dfa_node) {
		this.transitions[ch] = dfa_node;
	}

	toString() {
		var items = this.nfa_node_set.items;

        return items
	        .sort((a, b) => a.index - b.index)
	        .map(item => String(item.id))
	        .join(",");
	}
}

class NFAGraphConverter {
	constructor() {
		this.nfa_nodes = null;
		this.dfa_nodes = null;
	}

	createDFANode(nfa_node_set) {
		let id = this.dfa_nodes.length;
		let node = new DFANode(nfa_node_set, id);

		node.iod
		this.dfa_nodes.push(node);

		return node;
	}

	convert(nfa) {
		this.nfa_nodes = nfa.getNodes();
		this.dfa_nodes = [];

		this.createDFANode(
			this.getEpsilonReachable(
				nfa.start
			)
		);

		// keep processing dfa nodes until we reach the end of the list. Note
		// that // the list may grow with each iteration, so we can't cache the
		// node list length nor use forEach
		for (var i = 0; i < this.dfa_nodes.length; i++) {
            this.processTransitions(this.dfa_nodes[i]);
        }

		return this.dfa_nodes;
	}

	getEpsilonReachable(nfa_node) {
        var result = new ArraySet();

        // we can always get to ourself
        result.add(nfa_node)

        // keep expanding the result set, adding epsilon reachable nodes for
        // each new node added to the set
        for (var i = 0; i < result.size; i++) {
            var current_node = result.item(i);

            current_node.epsilon.forEach(item => result.add(item));
        }

        return result;
    }

    getTransitionReachable(nfa_node, ch) {
    	var result;

        if (nfa_node.hasCharacter(ch)) {
            result = this.getEpsilonReachable(nfa_node.next);
        }
        else {
            result = new ArraySet();
        }

        return result;
    }

    getDfaNodeByReachableStates(reachable) {
        var result = null;

        for (var i = 0; i < this.dfa_nodes.length; i++) {
            var dfa_node = this.dfa_nodes[i];

            if (dfa_node.nfa_node_set.equals(reachable)) {
                result = dfa_node;
                break;
            }
        }

        return result;
    }

    processTransitions(dfa_node) {
    	var nfa_nodes = dfa_node.nfa_node_set;

        for (var i = 0; i < 256; i++) {
            var reachable = new ArraySet();
            var ch = String.fromCharCode(i);

            for (var j = 0; j < nfa_nodes.size; j++) {
                var nfa_node = nfa_nodes.item(j);

                reachable.union(this.getTransitionReachable(nfa_node, ch));

                if (nfa_node.acceptState != -1 && dfa_node.acceptState != nfa_node.acceptState) {
                    var current = dfa_node.acceptState;
                    var candidate = nfa_node.acceptState;
                    var newValue = (current != -1) ? Math.min(current, candidate) : candidate;

                    if (current != newValue) {
                        dfa_node.acceptState = newValue;
                        //print("(" + current + "," + candidate + ") => " + newValue);
                    }
                }
	        }

            if (reachable.size > 0) {
                var target_dfa_node = this.getDfaNodeByReachableStates(reachable);

                if (target_dfa_node === null) {
                    target_dfa_node = this.createDFANode(reachable);
                }

                dfa_node.setTransition(ch, target_dfa_node);
            }
            else {
                dfa_node.setTransition(ch, null);
            }
        }
    }
}

module.exports = NFAGraphConverter;
<commit_msg>Emit converted DFA as a lookup table<commit_after>let ArraySet = require('./ArraySet');

class DFANode {
	constructor(nfa_node_set, id) {
		this.nfa_node_set = nfa_node_set;
		this.id = id;
		this.transitions = {};
		this.acceptState = -1;
	}

	getTransition(ch) {
		return (this.transitions.hasOwnProperty(ch)) ? this.transitions[ch] : null;
	}

	setTransition(ch, dfa_node) {
		this.transitions[ch] = dfa_node;
	}

	toString() {
		var items = this.nfa_node_set.items;

        return items
	        .sort((a, b) => a.index - b.index)
	        .map(item => String(item.id))
	        .join(",");
	}
}

class NFAGraphConverter {
	constructor() {
		this.nfa_nodes = null;
		this.dfa_nodes = null;
	}

	createDFANode(nfa_node_set) {
		let id = this.dfa_nodes.length;
		let node = new DFANode(nfa_node_set, id);

		node.iod
		this.dfa_nodes.push(node);

		return node;
	}

	convert(nfa) {
		this.nfa_nodes = nfa.getNodes();
		this.dfa_nodes = [];

		this.createDFANode(
			this.getEpsilonReachable(
				nfa.start
			)
		);

		// keep processing dfa nodes until we reach the end of the list. Note
		// that the list may grow with each iteration, so we can't cache the
		// node list length nor use forEach
		for (var i = 0; i < this.dfa_nodes.length; i++) {
            this.processTransitions(this.dfa_nodes[i]);
        }

        return this.generateTable()
	}

	getEpsilonReachable(nfa_node) {
        var result = new ArraySet();

        // we can always get to ourself
        result.add(nfa_node)

        // keep expanding the result set, adding epsilon reachable nodes for
        // each new node added to the set
        for (var i = 0; i < result.size; i++) {
            var current_node = result.item(i);

            current_node.epsilon.forEach(item => result.add(item));
        }

        return result;
    }

    getTransitionReachable(nfa_node, ch) {
    	var result;

        if (nfa_node.hasCharacter(ch)) {
            result = this.getEpsilonReachable(nfa_node.next);
        }
        else {
            result = new ArraySet();
        }

        return result;
    }

    getDfaNodeByReachableStates(reachable) {
        var result = null;

        for (var i = 0; i < this.dfa_nodes.length; i++) {
            var dfa_node = this.dfa_nodes[i];

            if (dfa_node.nfa_node_set.equals(reachable)) {
                result = dfa_node;
                break;
            }
        }

        return result;
    }

    processTransitions(dfa_node) {
    	var nfa_nodes = dfa_node.nfa_node_set;

        for (var i = 0; i < 256; i++) {
            var reachable = new ArraySet();
            var ch = String.fromCharCode(i);

            for (var j = 0; j < nfa_nodes.size; j++) {
                var nfa_node = nfa_nodes.item(j);

                reachable.union(this.getTransitionReachable(nfa_node, ch));

                if (nfa_node.acceptState != -1 && dfa_node.acceptState != nfa_node.acceptState) {
                    var current = dfa_node.acceptState;
                    var candidate = nfa_node.acceptState;
                    var newValue = (current != -1) ? Math.min(current, candidate) : candidate;

                    if (current != newValue) {
                        dfa_node.acceptState = newValue;
                        //print("(" + current + "," + candidate + ") => " + newValue);
                    }
                }
	        }

            if (reachable.size > 0) {
                var target_dfa_node = this.getDfaNodeByReachableStates(reachable);

                if (target_dfa_node === null) {
                    target_dfa_node = this.createDFANode(reachable);
                }

                dfa_node.setTransition(ch, target_dfa_node);
            }
            else {
                dfa_node.setTransition(ch, null);
            }
        }
    }

    generateTable() {
    	var table = [];

    	function emitMORLE(dfa_node) {
    		var emitCount = 0,
    			lastValue = null,
    			count = 0;

    		var result = [];

    		function emit() {
    			if (lastValue == -1) {
    				result.push(-count);
    			}
    			else if (count == 1) {
    				result.push(lastValue);
    			}
    			else {
    				result.push((count << 8) | lastValue);
    			}

    			emitCount++;
    		}

    		for (var i = 0; i < 256; i++) {
    			var ch = String.fromCharCode(i);
                var target_node = dfa_node.getTransition(ch);
				var value = (target_node === null) ? -1 : target_node.id;

				if (lastValue === null) {
					lastValue = value;
					count = 1;
				} else if (lastValue == value) {
                    count++;
                } else {
                    emit();

					lastValue = value;
					count = 1;
                }
    		}

    		emit();

    		return result;
    	}

    	this.dfa_nodes.forEach(dfa_node => {
    		var acceptState = dfa_node.acceptState;

    		// Minus One Run-Length Encoding
    		var entry = emitMORLE(dfa_node);

    		table.push([entry, acceptState]);
    	});

    	return table;
    }
}

module.exports = NFAGraphConverter;
<|endoftext|>


<commit_before>/**
 * jQuery Formset 1.3-pre
 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
 * @requires jQuery 1.2.6 or later
 *
 * Copyright (c) 2009, Stanislaus Madueke
 * All rights reserved.
 *
 * Licensed under the New BSD License
 * See: http://www.opensource.org/licenses/bsd-license.php
 */

/**
 * Events
 *
 * initialized.formset -- Triggered when a formset is first initialized.
 * row_removed.formset -- Triggered when a row is removed. Receives the
 *                        removed row as an extra parameter if it's
 *                        hidden rather than destroyed.
 * row_added.formset   -- Triggered when a row is added. Receives the
 *                        new row as an extra parameter.
 */

;(function($) {
    "use strict";

    // Formset Class Definition
    // ========================

    var Formset = function (el, options) {
        this.options = $.extend({}, Formset.DEFAULTS, options);
        this.$el = $(el);
        this.totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS');
        this.maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS');

        this.init();
    };

    Formset.DEFAULTS = {
        prefix: 'form',                  // The form prefix for your django formset
        rowSelector: null,               // The jQuery selector to identify rows of the formset
        formTemplate: null,              // The jQuery selection cloned to generate new form instances
        addTrigger: 'Add Another',
        deleteTrigger: 'Remove',
        deleteWrapper: null,             // jQuery selector for which element delete button should be appended to
        addCssClass: 'add-row',          // CSS class applied to the add link
        addWrapper: null,                // jQuery selector for which element add button should be appended to
        deleteCssClass: 'delete-row',    // CSS class applied to the delete link
        formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset
        keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned
        sortableHandle: null,            // jQuery selector for what part of each form row is draggable
        sortableField: null,             // Name of field which keeps track of order index
    };

    Formset.childElementSelector = 'input,select,textarea,label,div';

    Formset.log = function () {
        /*global console:true */
        if (window.console && console.log)
            console.log('[formset] ' + Array.prototype.join.call(arguments, ' ') );
    };
    Formset.warn = function () {
        if (window.console && console.log)
            console.warn('[formset] ' + Array.prototype.join.call(arguments, ' ') );
    }

    Formset.prototype.init = function () {
        // Find all children of wrapper or all descendents matching options.rowSelector:
        var formset = this, // useful for subscope below
            options = this.options,
            initial_rows = this.current_rows();

        // Initialize each of the current rows:
        initial_rows.each(function () {
            var row = $(this),
                del = row.find('input:checkbox[id $= "-DELETE"]');
            if (del.length) {
                // If you specify "can_delete = True" when creating an inline formset,
                // Django adds a checkbox to each form in the formset.
                // Replace the default checkbox with a hidden field:
                if (del.is(':checked')) {
                    // If an inline formset containing deleted forms fails validation, make sure
                    // we keep the forms hidden (thanks for the bug report and suggested fix Mike)
                    del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" value="on" />');
                    row.hide();
                } else {
                    del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
                }
                // Hide any labels associated with the DELETE checkbox:
                $('label[for="' + del.attr('id') + '"]').hide();
                del.remove();
            }
            row.addClass(options.formCssClass);
            if (row.is(':visible')) {
                formset.insertDeleteLink(row);
            }
        });

        this.insertAddLink();

        // If sortableField is set, initialize sortables
        if (options.sortableField !== null) this.initSortable();

        // Trigger the initialized event:
        this.$el.trigger('initialized.formset');
        Formset.log("Initialized formset with " + initial_rows.length + " initial rows.");
    };

    Formset.prototype.initSortable = function () {
        var formset = this, // useful for subscope below
            options = this.options,
            sortable_options = {opacity: .5, axis: "y"};

        if (!("sortable" in $.fn)) {
            // If jQuery UI sortable is not included, short-circuit:
            Formset.warn("jQuery UI Sortable component required for sortable formsets. http://jqueryui.com/");
            return;
        }

        // If a row selector is specified, limit sortables to that selector:
        if (options.rowSelector !== null) sortable_options.items = options.rowSelector;
        // If a handle is specified:
        if (options.sortableHandle !== null) sortable_options.handle = options.sortableHandle;
        // Add a callback for renumbering the fields:
        sortable_options.update = function (e, data) {
            formset.refreshRowOrder();
        };

        this.$el.sortable(sortable_options);

        Formset.log("Initialized drag-and-drop sorting.")
    };

    Formset.prototype.refreshRowOrder = function () {
        var formset = this,
            options = this.options,
            rows = this.current_rows().filter(":visible"); // If a row is hidden, assume it's been deleted.
        rows.each(function (i, v) {
            var sortableFieldId;
            formset.updateRowIndex($(this), i);
            if (formset.options.sortableField) {
                sortableFieldId = ["id_", options.prefix, "-", i, "-", options.sortableField].join("");
                $("#" + sortableFieldId).val(i+1);
            };
        });
    }

    Formset.prototype.current_rows = function () {
        var options = this.options;
        return (options.rowSelector === null) ? this.$el.children() : this.$el.find(options.rowSelector);
    };

    Formset.prototype.insertAddLink = function () {
        // Generate the add button:
        var formset = this, // useful for subscope below
            options = this.options,
            add_link = this.add_link = $(options.addTrigger),
            current_rows = this.current_rows(),
            hideAddButton = !this.showAddButton(),
                addButton, template;
            if (options.formTemplate) {
                // If a form template was specified, we'll clone it to generate new form instances:
                template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
            } else {
                // Otherwise, use the last form in the formset; this works much better if you've got
                // extra (>= 1) forms (thnaks to justhamade for pointing this out):
                template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
                template.find('input:hidden[id $= "-DELETE"]').remove();
                // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
                template.find(Formset.childElementSelector).not(options.keepFieldValues).each(function() {
                    var elem = $(this);
                    // If this is a checkbox or radiobutton, uncheck it.
                    // This fixes Issue 1, reported by Wilson.Andrew.J:
                    if (elem.is('input:checkbox') || elem.is('input:radio')) {
                        elem.attr('checked', false);
                    } else {
                        elem.val('');
                    }
                });
            }
            // FIXME: Perhaps using $.data would be a better idea?
            options.formTemplate = template;

            // Generate the add button.
            if (options.addWrapper !== null) {
                // If a wrapper selector is specified, append the add
                // button to the element matching that selector.
                $(options.addWrapper).append(add_link);
            } else if (current_rows.attr('tagName') == 'TR') {
                // If forms are laid out as table rows, insert the
                // "add" button in a new table row:
                var numCols = current_rows.eq(0).children().length,   // This is a bit of an assumption :|
                    buttonRow = $('

').addClass(options.formCssClass + '-add');
                buttonRow.find('td').append(add_link)
                current_rows.parent().append(buttonRow);
                if (hideAddButton) buttonRow.hide();
            } else {
                // Otherwise, insert it immediately after the last form:
                current_rows.filter(':last').after(add_link);
                if (hideAddButton) add_link.hide();
            }
            add_link.click(function (e) {
                e.preventDefault();
                formset.addRow();
            });
    };

    Formset.prototype.insertDeleteLink = function (row) {
        var options = this.options,
            // Create a new DOM element:
            delete_link = $(options.deleteTrigger);
        // Store the associated row as data on the delete link:
        delete_link.data('formset.row', row);
        // Store the associated formset as data on the delete link:
        delete_link.data('formset', this);
        // Find the appropriate place to append the delete link:
        if (options.deleteWrapper !== null){
            // If a wrapper selector is specified, append to an
            // element matching that selector within the row:
            row.find(options.deleteWrapper).append(delete_link)
        } else if (row.is('tr')) {
            // If the forms are laid out in table rows, insert
            // the remove button into the last table cell:
            row.children(':last').append(delete_link);
        } else if (row.is('ul') || row.is('OL')) {
            // If they're laid out as an ordered/unordered list,
            // insert an
 after the last list item:
            row.append(delete_link.wrap('

'));
        } else {
            // Otherwise, just insert the remove button as the
            // last child element of the form's container:
            row.append(delete_link);
        }
        // Bind the click event for the delete link:
        delete_link.click(function(e) {
            var $this = $(this),
                row = $this.data('formset.row'),
                formset = $this.data('formset');
            e.preventDefault()
            return formset.removeRow(row);
        });

        Formset.log("Added delete link to row.");
    };

    Formset.prototype.removeRow = function (row) {
        // Remove a row, with the row passed as a jQuery object.
        var formset = this, // useful for subscope below
            options = this.options,
            del = row.find('input:hidden[id $= "-DELETE"]'),
            buttonRow = $(this.add_link).parents('tr.' + options.formCssClass + '-add').get(0) ? $(this.add_link).parents('tr.' + options.formCssClass + '-add') : this.add_link,
            forms;
        if (del.length) {
            // We're dealing with an inline formset.
            // Rather than remove this form from the DOM, we'll mark it as deleted
            // and hide it, then let Django handle the deleting:
            del.val('on');
            row.hide();
            forms = $('.' + options.formCssClass).not(':hidden');
        } else {
            row.remove();
            // Update the TOTAL_FORMS count:
            forms = this.current_rows();
            this.totalForms.val(forms.length);
        }
        for (var i=0, formCount=this.current_rows().length; i<formCount; i++) {
            if (!del.length) {
                // Also update names and IDs for all child controls (if this isn't
                // a delete-able inline formset) so they remain in sequence:
                forms.eq(i).find(Formset.childElementSelector).each(function() {
                    formset.updateElementIndex($(this), i);
                });
            }
        }

        // Check if we need to show the add button:
        if (buttonRow.is(':hidden') && this.showAddButton()) buttonRow.show();

        // Trigger the row_removed event:
        this.$el.trigger('row_removed.formset', [row]);
        Formset.log("Removed a row.");

        return false;
    };

    Formset.prototype.addRow = function (row) {
        var formset = this, // useful for subscope below
            options = this.options,
            formCount = parseInt(this.totalForms.val()),
            row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
            buttonRow = $(this.add_link).parents('tr.' + options.formCssClass + '-add').get(0) ? $(this.add_link).parents('tr.' + options.formCssClass + '-add') : null;
        if (buttonRow !== null) {
            // If this is a table, insert before the button row.
            row.insertBefore(buttonRow).show();
        } else {
            this.current_rows().filter(':last').after(row)
        }
        this.insertDeleteLink(row);
        this.updateRowIndex(row, formCount);
        this.totalForms.val(formCount + 1);
        // Check if we've exceeded the maximum allowed number of forms:
        if (buttonRow !== null) {
            // If it's a table, hide the hold row:
            if (!this.showAddButton()) buttonRow.hide();
        } else {
            if (!this.showAddButton()) this.add_link.hide();
        }
        // If a post-add callback was supplied, call it with the added form:
        if (options.added) options.added(row);

        // Trigger the row_added event:
        this.$el.trigger('row_added.formset', [row]);
        Formset.log("Added a row. Current row count: " + this.totalForms.val() + ". Max row count: " + this.maxForms.val() + ".");

        return false;
    };

    Formset.prototype.updateRowIndex = function (row, ndx) {
        var formset = this;
        row.find(Formset.childElementSelector).each(function() {
            formset.updateElementIndex($(this), ndx);
        });
    };

    Formset.prototype.showAddButton = function () {
        return this.maxForms.length == 0 ||   // For Django versions pre 1.2
            (this.maxForms.val() == '' || (this.maxForms.val() - this.totalForms.val() > 0))
    };

    Formset.prototype.updateElementIndex = function(elem, ndx) {
        var prefix = this.options.prefix,
            idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-'),
            replacement = prefix + '-' + ndx + '-';
        if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
        if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
        if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
    },

    // Plugin Definition
    // =================

    $.fn.formset = function (options) {
        // Should be called on an element that is a parent or ancestor
        // of the formset rows.
        return this.each(function () {
            var $this = $(this),
                data = $(this).data('formset'),
                options_ = typeof options == 'object' && options;
            // Instatiate formset on element if it not already.
            if (!data) return $this.data('formset', new Formset(this, options_));
            // If a string was passed to the function, interpret as an API command.
            if (typeof options_ == 'string') return data[option_]();
        });
    };

})(jQuery);
<commit_msg>Added an event and console message.<commit_after>/**
 * jQuery Formset 1.3-pre
 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
 * @requires jQuery 1.2.6 or later
 *
 * Copyright (c) 2009, Stanislaus Madueke
 * All rights reserved.
 *
 * Licensed under the New BSD License
 * See: http://www.opensource.org/licenses/bsd-license.php
 */

/**
 * Events
 *
 * initialized.formset -- Triggered when a formset is first initialized.
 * row_removed.formset -- Triggered when a row is removed. Receives the
 *                        removed row as an extra parameter if it's
 *                        hidden rather than destroyed.
 * row_added.formset   -- Triggered when a row is added. Receives the
 *                        new row as an extra parameter.
 * reordered.formset   -- Triggered when the order of rows is changed by user
 *                        drag and drop.
 */

;(function($) {
    "use strict";

    // Formset Class Definition
    // ========================

    var Formset = function (el, options) {
        this.options = $.extend({}, Formset.DEFAULTS, options);
        this.$el = $(el);
        this.totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS');
        this.maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS');

        this.init();
    };

    Formset.DEFAULTS = {
        prefix: 'form',                  // The form prefix for your django formset
        rowSelector: null,               // The jQuery selector to identify rows of the formset
        formTemplate: null,              // The jQuery selection cloned to generate new form instances
        addTrigger: 'Add Another',
        deleteTrigger: 'Remove',
        deleteWrapper: null,             // jQuery selector for which element delete button should be appended to
        addCssClass: 'add-row',          // CSS class applied to the add link
        addWrapper: null,                // jQuery selector for which element add button should be appended to
        deleteCssClass: 'delete-row',    // CSS class applied to the delete link
        formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset
        keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned
        sortableHandle: null,            // jQuery selector for what part of each form row is draggable
        sortableField: null,             // Name of field which keeps track of order index
    };

    Formset.childElementSelector = 'input,select,textarea,label,div';

    Formset.log = function () {
        /*global console:true */
        if (window.console && console.log)
            console.log('[formset] ' + Array.prototype.join.call(arguments, ' ') );
    };
    Formset.warn = function () {
        if (window.console && console.log)
            console.warn('[formset] ' + Array.prototype.join.call(arguments, ' ') );
    }

    Formset.prototype.init = function () {
        // Find all children of wrapper or all descendents matching options.rowSelector:
        var formset = this, // useful for subscope below
            options = this.options,
            initial_rows = this.current_rows();

        // Initialize each of the current rows:
        initial_rows.each(function () {
            var row = $(this),
                del = row.find('input:checkbox[id $= "-DELETE"]');
            if (del.length) {
                // If you specify "can_delete = True" when creating an inline formset,
                // Django adds a checkbox to each form in the formset.
                // Replace the default checkbox with a hidden field:
                if (del.is(':checked')) {
                    // If an inline formset containing deleted forms fails validation, make sure
                    // we keep the forms hidden (thanks for the bug report and suggested fix Mike)
                    del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" value="on" />');
                    row.hide();
                } else {
                    del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
                }
                // Hide any labels associated with the DELETE checkbox:
                $('label[for="' + del.attr('id') + '"]').hide();
                del.remove();
            }
            row.addClass(options.formCssClass);
            if (row.is(':visible')) {
                formset.insertDeleteLink(row);
            }
        });

        this.insertAddLink();

        // If sortableField is set, initialize sortables
        if (options.sortableField !== null) this.initSortable();

        // Trigger the initialized event:
        this.$el.trigger('initialized.formset');
        Formset.log("Initialized formset with " + initial_rows.length + " initial rows.");
    };

    Formset.prototype.initSortable = function () {
        var formset = this, // useful for subscope below
            options = this.options,
            sortable_options = {opacity: .5, axis: "y"};

        if (!("sortable" in $.fn)) {
            // If jQuery UI sortable is not included, short-circuit:
            Formset.warn("jQuery UI Sortable component required for sortable formsets. http://jqueryui.com/");
            return;
        }

        // If a row selector is specified, limit sortables to that selector:
        if (options.rowSelector !== null) sortable_options.items = options.rowSelector;
        // If a handle is specified:
        if (options.sortableHandle !== null) sortable_options.handle = options.sortableHandle;
        // Add a callback for renumbering the fields:
        sortable_options.update = function (e, data) {
            formset.refreshRowOrder();
            // Trigger a reorder event
            formset.$el.trigger('reordered.formset');
            Formset.log("Formset items reordered.");
        };

        this.$el.sortable(sortable_options);

        Formset.log("Initialized drag-and-drop sorting.")
    };

    Formset.prototype.refreshRowOrder = function () {
        var formset = this,
            options = this.options,
            rows = this.current_rows().filter(":visible"); // If a row is hidden, assume it's been deleted.
        rows.each(function (i, v) {
            var sortableFieldId;
            formset.updateRowIndex($(this), i);
            if (formset.options.sortableField) {
                sortableFieldId = ["id_", options.prefix, "-", i, "-", options.sortableField].join("");
                $("#" + sortableFieldId).val(i+1);
            };
        });
    }

    Formset.prototype.current_rows = function () {
        var options = this.options;
        return (options.rowSelector === null) ? this.$el.children() : this.$el.find(options.rowSelector);
    };

    Formset.prototype.insertAddLink = function () {
        // Generate the add button:
        var formset = this, // useful for subscope below
            options = this.options,
            add_link = this.add_link = $(options.addTrigger),
            current_rows = this.current_rows(),
            hideAddButton = !this.showAddButton(),
                addButton, template;
            if (options.formTemplate) {
                // If a form template was specified, we'll clone it to generate new form instances:
                template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
            } else {
                // Otherwise, use the last form in the formset; this works much better if you've got
                // extra (>= 1) forms (thnaks to justhamade for pointing this out):
                template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
                template.find('input:hidden[id $= "-DELETE"]').remove();
                // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
                template.find(Formset.childElementSelector).not(options.keepFieldValues).each(function() {
                    var elem = $(this);
                    // If this is a checkbox or radiobutton, uncheck it.
                    // This fixes Issue 1, reported by Wilson.Andrew.J:
                    if (elem.is('input:checkbox') || elem.is('input:radio')) {
                        elem.attr('checked', false);
                    } else {
                        elem.val('');
                    }
                });
            }
            // FIXME: Perhaps using $.data would be a better idea?
            options.formTemplate = template;

            // Generate the add button.
            if (options.addWrapper !== null) {
                // If a wrapper selector is specified, append the add
                // button to the element matching that selector.
                $(options.addWrapper).append(add_link);
            } else if (current_rows.attr('tagName') == 'TR') {
                // If forms are laid out as table rows, insert the
                // "add" button in a new table row:
                var numCols = current_rows.eq(0).children().length,   // This is a bit of an assumption :|
                    buttonRow = $('

').addClass(options.formCssClass + '-add');
                buttonRow.find('td').append(add_link)
                current_rows.parent().append(buttonRow);
                if (hideAddButton) buttonRow.hide();
            } else {
                // Otherwise, insert it immediately after the last form:
                current_rows.filter(':last').after(add_link);
                if (hideAddButton) add_link.hide();
            }
            add_link.click(function (e) {
                e.preventDefault();
                formset.addRow();
            });
    };

    Formset.prototype.insertDeleteLink = function (row) {
        var options = this.options,
            // Create a new DOM element:
            delete_link = $(options.deleteTrigger);
        // Store the associated row as data on the delete link:
        delete_link.data('formset.row', row);
        // Store the associated formset as data on the delete link:
        delete_link.data('formset', this);
        // Find the appropriate place to append the delete link:
        if (options.deleteWrapper !== null){
            // If a wrapper selector is specified, append to an
            // element matching that selector within the row:
            row.find(options.deleteWrapper).append(delete_link)
        } else if (row.is('tr')) {
            // If the forms are laid out in table rows, insert
            // the remove button into the last table cell:
            row.children(':last').append(delete_link);
        } else if (row.is('ul') || row.is('OL')) {
            // If they're laid out as an ordered/unordered list,
            // insert an
 after the last list item:
            row.append(delete_link.wrap('

'));
        } else {
            // Otherwise, just insert the remove button as the
            // last child element of the form's container:
            row.append(delete_link);
        }
        // Bind the click event for the delete link:
        delete_link.click(function(e) {
            var $this = $(this),
                row = $this.data('formset.row'),
                formset = $this.data('formset');
            e.preventDefault()
            return formset.removeRow(row);
        });

        Formset.log("Added delete link to row.");
    };

    Formset.prototype.removeRow = function (row) {
        // Remove a row, with the row passed as a jQuery object.
        var formset = this, // useful for subscope below
            options = this.options,
            del = row.find('input:hidden[id $= "-DELETE"]'),
            buttonRow = $(this.add_link).parents('tr.' + options.formCssClass + '-add').get(0) ? $(this.add_link).parents('tr.' + options.formCssClass + '-add') : this.add_link,
            forms;
        if (del.length) {
            // We're dealing with an inline formset.
            // Rather than remove this form from the DOM, we'll mark it as deleted
            // and hide it, then let Django handle the deleting:
            del.val('on');
            row.hide();
            forms = $('.' + options.formCssClass).not(':hidden');
        } else {
            row.remove();
            // Update the TOTAL_FORMS count:
            forms = this.current_rows();
            this.totalForms.val(forms.length);
        }
        for (var i=0, formCount=this.current_rows().length; i<formCount; i++) {
            if (!del.length) {
                // Also update names and IDs for all child controls (if this isn't
                // a delete-able inline formset) so they remain in sequence:
                forms.eq(i).find(Formset.childElementSelector).each(function() {
                    formset.updateElementIndex($(this), i);
                });
            }
        }

        // Check if we need to show the add button:
        if (buttonRow.is(':hidden') && this.showAddButton()) buttonRow.show();

        // Trigger the row_removed event:
        this.$el.trigger('row_removed.formset', [row]);
        Formset.log("Removed a row.");

        return false;
    };

    Formset.prototype.addRow = function (row) {
        var formset = this, // useful for subscope below
            options = this.options,
            formCount = parseInt(this.totalForms.val()),
            row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
            buttonRow = $(this.add_link).parents('tr.' + options.formCssClass + '-add').get(0) ? $(this.add_link).parents('tr.' + options.formCssClass + '-add') : null;
        if (buttonRow !== null) {
            // If this is a table, insert before the button row.
            row.insertBefore(buttonRow).show();
        } else {
            this.current_rows().filter(':last').after(row)
        }
        this.insertDeleteLink(row);
        this.updateRowIndex(row, formCount);
        this.totalForms.val(formCount + 1);
        // Check if we've exceeded the maximum allowed number of forms:
        if (buttonRow !== null) {
            // If it's a table, hide the hold row:
            if (!this.showAddButton()) buttonRow.hide();
        } else {
            if (!this.showAddButton()) this.add_link.hide();
        }
        // If a post-add callback was supplied, call it with the added form:
        if (options.added) options.added(row);

        // Trigger the row_added event:
        this.$el.trigger('row_added.formset', [row]);
        Formset.log("Added a row. Current row count: " + this.totalForms.val() + ". Max row count: " + this.maxForms.val() + ".");

        return false;
    };

    Formset.prototype.updateRowIndex = function (row, ndx) {
        var formset = this;
        row.find(Formset.childElementSelector).each(function() {
            formset.updateElementIndex($(this), ndx);
        });
    };

    Formset.prototype.showAddButton = function () {
        return this.maxForms.length == 0 ||   // For Django versions pre 1.2
            (this.maxForms.val() == '' || (this.maxForms.val() - this.totalForms.val() > 0))
    };

    Formset.prototype.updateElementIndex = function(elem, ndx) {
        var prefix = this.options.prefix,
            idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-'),
            replacement = prefix + '-' + ndx + '-';
        if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
        if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
        if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
    },

    // Plugin Definition
    // =================

    $.fn.formset = function (options) {
        // Should be called on an element that is a parent or ancestor
        // of the formset rows.
        return this.each(function () {
            var $this = $(this),
                data = $(this).data('formset'),
                options_ = typeof options == 'object' && options;
            // Instatiate formset on element if it not already.
            if (!data) return $this.data('formset', new Formset(this, options_));
            // If a string was passed to the function, interpret as an API command.
            if (typeof options_ == 'string') return data[option_]();
        });
    };

})(jQuery);
<|endoftext|>


<commit_before>// Before compile time (prep time), this (and everything else in this folder) is moved to
// ${pushkin_front_end_quizzes_dir}, so all paths to modules located outside of this
// folder are relative to that root

import React from 'react';
import { browserHistory } from 'react-router';

import s from './styles.scss';
import jsPsychStyles from '../libraries/jsPsych/css/jspsych.css';
import jsPsychTimeline from './quiz_files/jsPsychTimeline';
// jsPsych isn't actually a "module" like normal modules are in node/commonJS
// it needs to be required globally and not assigned to a variable
require('../libraries/jsPsych/jspsych.js');
require('../libraries/jsPsych/plugins/jspsych-instructions.js');

export default class QUIZ_NAME extends React.Component {

	constructor(props) {
		super(props);
		this.state = { loading: true };
		browserHistory.listen(() => {
		  jsPsych.endExperiment();
		});
	};

	componentDidMount() {
		jsPsych.init({
			display_element: this.refs.jsPsychTarget,
			timeline: jsPsychTimeline
		});
	};

	render() {

		return (

				{/* <link>s only go in  ideally
					also, import them– that's how webpack reduces load time and requests and stuff
					<link
					rel="stylesheet"
					type="text/css"
					href={`${baseUrl}/css/jspsych.css`}
				/>*/}
				{/*

							Loading...

${QUIZ_NAME}

				*/}

		);
	}
}
<commit_msg>goose<commit_after>// Before compile time (prep time), this (and everything else in this folder) is moved to
// ${pushkin_front_end_quizzes_dir}, so all paths to modules located outside of this
// folder are relative to that root

import React from 'react';
import { browserHistory } from 'react-router';

import s from './styles.scss';
import jsPsychStyles from '../libraries/jsPsych/css/jspsych.css';
import jsPsychTimeline from './quiz_files/jsPsychTimeline';
// jsPsych isn't actually a "module" like normal modules are in node/commonJS
// it needs to be required globally and not assigned to a variable
require('../libraries/jsPsych/jspsych.js');
require('../libraries/jsPsych/plugins/jspsych-instructions.js');

export default class QUIZ_NAME extends React.Component {

	constructor(props) {
		super(props);
		this.state = { loading: true };
		browserHistory.listen(() => {
		  jsPsych.endExperiment();
		});
	};

	componentDidMount() {
		jsPsych.init({
			display_element: this.refs.jsPsychTarget,
			timeline: jsPsychTimeline
		});
	};

	render() {

		return (

		);
	}
}
<|endoftext|>


<commit_before>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */

 /**
  * @class
  */
OpenLayers.Events = Class.create();
OpenLayers.Events.prototype = {

    /** @final @type Array: supported events */
    BROWSER_EVENTS: [
        "mouseover", "mouseout",
        "mousedown", "mouseup", "mousemove",
        "click", "dblclick",
        "resize", "focus", "blur"
    ],

    /** @type Hash of Array(Function): events listener functions */
    listeners: null,

    /** @type Object: the code object issuing application events */
    object: null,

    /** @type DOMElement: the DOM element receiving browser events */
    div: null,

    /** @type Array: list of support application events */
    eventTypes: null,

    /**
     * @constructor
     *
     * @param {OpenLayers.Map} object The js object to which this Events object
     *                                is being added
     * @param {DOMElement} div A dom element to respond to browser events
     * @param {Array} eventTypes Array of custom application events
     */
    initialize: function (object, div, eventTypes) {
        this.listeners  = {};
        this.object     = object;
        this.div        = div;
        this.eventTypes = eventTypes;

        if (eventTypes) {
            for (var i = 0; i < this.eventTypes.length; i++) {
                // create a listener list for every custom application event
                this.listeners[ this.eventTypes[i] ] = [];
            }
        }

        for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
            var eventType = this.BROWSER_EVENTS[i];

            // every browser event has a corresponding application event
            // (whether it's listened for or not).
            this.listeners[ eventType ] = [];

            Event.observe(div, eventType,
                this.handleBrowserEvent.bindAsEventListener(this));
        }

        // disable dragstart in IE so that mousedown/move/up works normally
        Event.observe(div, "dragstart", Event.stop);
    },

    /**
     * @param {String} type Name of the event to register
     * @param {Object} obj The object to bind the context to for the callback
     * @param {Function} func The callback function
     */
    register: function (type, obj, func) {
        if (func == null) {
            obj = this.object;
            func = obj;
        }
        var listeners = this.listeners[type];
        listeners.push( {obj: obj, func: func} );
    },

    /**
     * @param {String} type
     * @param {Object} obj
     * @param {Function} func
     */
    unregister: function (type, obj, func) {
        var listeners = this.listeners[type];
        for (var i = 0; i < listeners.length; i++) {
            if (listeners[i].obj == obj && listeners[i].type == type) {
                listeners.splice(i, 1);
                break;
            }
        }
    },

    /**
     * @param {String} type
     */
    remove: function(type) {
        this.listeners[type].pop();
    },

    /** Trigger a specified registered event
     *
     * @param {String} type
     * @param {Event} evt
     */
    triggerEvent: function (type, evt) {
        if (evt == null) {
            evt = {};
        }
        evt.object = this.object;
        evt.div = this.div;

        var listeners = this.listeners[type];
        for (var i = 0; i < listeners.length; i++) {
            var callback = listeners[i];
            var continueChain = callback.func.call(callback.obj, evt);
            if (continueChain != null && !continueChain) break;
        }
    },

    /** Basically just a wrapper to the triggerEvent() function, but takes
     *   care to set a property 'xy' on the event with the current mouse
     *   position.
     *
     * @private
     *
     * @param {event} evt
     */
    handleBrowserEvent: function (evt) {
        evt.xy = this.getMousePosition(evt);
        this.triggerEvent(evt.type, evt)
    },

    /**
     * @private
     *
     * @param {event} evt
     *
     * @returns The current xy coordinate of the mouse, adjusted for offsets
     * @type OpenLayers.Pixel
     */
    getMousePosition: function (evt) {
        if (!this.div.offsets) {
            this.div.offsets = Position.page(this.div);
        }
        return new OpenLayers.Pixel(
                        evt.clientX - this.div.offsets[0],
                        evt.clientY - this.div.offsets[1]);
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Events"
};
<commit_msg>adding commenting/readability to triggerEvent()<commit_after>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */

 /**
  * @class
  */
OpenLayers.Events = Class.create();
OpenLayers.Events.prototype = {

    /** @final @type Array: supported events */
    BROWSER_EVENTS: [
        "mouseover", "mouseout",
        "mousedown", "mouseup", "mousemove",
        "click", "dblclick",
        "resize", "focus", "blur"
    ],

    /** @type Hash of Array(Function): events listener functions */
    listeners: null,

    /** @type Object: the code object issuing application events */
    object: null,

    /** @type DOMElement: the DOM element receiving browser events */
    div: null,

    /** @type Array: list of support application events */
    eventTypes: null,

    /**
     * @constructor
     *
     * @param {OpenLayers.Map} object The js object to which this Events object
     *                                is being added
     * @param {DOMElement} div A dom element to respond to browser events
     * @param {Array} eventTypes Array of custom application events
     */
    initialize: function (object, div, eventTypes) {
        this.listeners  = {};
        this.object     = object;
        this.div        = div;
        this.eventTypes = eventTypes;

        if (eventTypes) {
            for (var i = 0; i < this.eventTypes.length; i++) {
                // create a listener list for every custom application event
                this.listeners[ this.eventTypes[i] ] = [];
            }
        }

        for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
            var eventType = this.BROWSER_EVENTS[i];

            // every browser event has a corresponding application event
            // (whether it's listened for or not).
            this.listeners[ eventType ] = [];

            Event.observe(div, eventType,
                this.handleBrowserEvent.bindAsEventListener(this));
        }

        // disable dragstart in IE so that mousedown/move/up works normally
        Event.observe(div, "dragstart", Event.stop);
    },

    /**
     * @param {String} type Name of the event to register
     * @param {Object} obj The object to bind the context to for the callback
     * @param {Function} func The callback function
     */
    register: function (type, obj, func) {
        if (func == null) {
            obj = this.object;
            func = obj;
        }
        var listeners = this.listeners[type];
        listeners.push( {obj: obj, func: func} );
    },

    /**
     * @param {String} type
     * @param {Object} obj
     * @param {Function} func
     */
    unregister: function (type, obj, func) {
        var listeners = this.listeners[type];
        for (var i = 0; i < listeners.length; i++) {
            if (listeners[i].obj == obj && listeners[i].type == type) {
                listeners.splice(i, 1);
                break;
            }
        }
    },

    /**
     * @param {String} type
     */
    remove: function(type) {
        this.listeners[type].pop();
    },

    /** Trigger a specified registered event
     *
     * @param {String} type
     * @param {Event} evt
     */
    triggerEvent: function (type, evt) {

        // prep evt object with object & div references
        if (evt == null) {
            evt = new Object();
        }
        evt.object = this.object;
        evt.div = this.div;

        // execute all callbacks registered for specified type
        var listeners = this.listeners[type];
        for (var i = 0; i < listeners.length; i++) {
            var callback = listeners[i];

            // use the 'call' method to bind the context to callback.obj
            var continueChain = callback.func.call(callback.obj, evt);

            if ((continueChain != null) && (continueChain == false)) {
                // if callback returns false, execute no more callbacks.
                break;
            }
        }
    },

    /** Basically just a wrapper to the triggerEvent() function, but takes
     *   care to set a property 'xy' on the event with the current mouse
     *   position.
     *
     * @private
     *
     * @param {event} evt
     */
    handleBrowserEvent: function (evt) {
        evt.xy = this.getMousePosition(evt);
        this.triggerEvent(evt.type, evt)
    },

    /**
     * @private
     *
     * @param {event} evt
     *
     * @returns The current xy coordinate of the mouse, adjusted for offsets
     * @type OpenLayers.Pixel
     */
    getMousePosition: function (evt) {
        if (!this.div.offsets) {
            this.div.offsets = Position.page(this.div);
        }
        return new OpenLayers.Pixel(
                        evt.clientX - this.div.offsets[0],
                        evt.clientY - this.div.offsets[1]);
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Events"
};
<|endoftext|>


<commit_before>const SDPManager	= require("./SDPManager");

const SemanticSDP	= require("semantic-sdp");

const SDPInfo		= SemanticSDP.SDPInfo;
const Setup		= SemanticSDP.Setup;
const MediaInfo		= SemanticSDP.MediaInfo;
const CandidateInfo	= SemanticSDP.CandidateInfo;
const DTLSInfo		= SemanticSDP.DTLSInfo;
const ICEInfo		= SemanticSDP.ICEInfo;
const StreamInfo	= SemanticSDP.StreamInfo;
const TrackInfo		= SemanticSDP.TrackInfo;
const SourceGroupInfo	= SemanticSDP.SourceGroupInfo;
const Direction 	=	SemanticSDP.Direction;

class SDPManagerUnified extends SDPManager
{
	constructor(endpoint,capabilities)
	{
		//Init parent
		super();

		//Store params
		this.endpoint = endpoint;
		this.capabilities = capabilities;
		//The list of transceivers
		this.transceivers = [];
		//The pending list of local tracks not assigned to transceivers
		this.pending = new Set();
		//Set of removed local tracks
		this.removed = new Set();

		//Renegotiation needed flag
		this.renegotiationNeeded = false;

	}

	createLocalDescription()
	{
		//If there is no local info
		if (!this.localInfo)
		{
			//Create initial with
			this.localInfo = SDPInfo.create({
				dtls		: new DTLSInfo(Setup.ACTPASS,"sha-256",this.endpoint.getDTLSFingerprint()),
				ice		: ICEInfo.generate(true),
				candidates	: this.endpoint.getLocalCandidates()
			});
			//For each media capability
			for (const media of Object.keys(this.capabilities))
			{
				//New mid
				const mid = String(this.transceivers.length);
				//Add new transceiver
				this.transceivers.push({
					mid	: mid,
					media	: media,
					remote	: {},
					local	: {}
				});
				//Create new media info
				const mediaInfo = MediaInfo.create(media,this.capabilities[media]);
				//Set mid
				mediaInfo.setId(mid);
				//Add to local info
				this.localInfo.addMedia(mediaInfo);
			}
		}

		//First process all removed tracks
		for (const track of this.removed)
			//Check the transceivers
			for (const transceiver of this.transceivers)
				//Was it removed?
				if (transceiver.local.track == track)
				{
					//Clean transceiver
					delete(transceiver.local.track);
					delete(transceiver.local.stream);
					//Clean from removed
					this.removed.delete(track);
				}

		//Check if we can add new transceicers
		if (["initial","stable"].includes(this.state))
		{
			//For all pending transceivers
			for (const pending of this.pending)
			{
				//TODO: Check if we can reuse any empty
				/*
				 let found = false;

				for (const transceiver of this.transceivers)
				{
					 //Check new direction for local stuff
					switch(mediaInfo.getDirection())
					{
						case Direction.INACTIVE:
						case Direction.SENDONLY:
							//If we had one track on this
							if (transceiver.local.track)
								//Stop it
								transceiver.local.track.stop();
							//Delete it from transceiver
							delete (transceiver.local.track);
							break;
						case Direction.SENDRECV:
						case Direction.RECVONLY:
							//if we don't have a track and we had pending for adding
							if (!transceiver.local.track && this.pending.size)
							{
								console.log("--adding pending to transceiver mid:"+transceiver.mid + " i:"+i);
								//Get first one and remove it
								const first = this.pending.values().next();
								//Add it to the localInfo
								transceiver.local.track  = first.track;
								transceiver.local.stream = first.stream;
								//Remove from set
								this.pending.delete(first);
							}
							break;
					}
				}
				if (!found).. the following
				*/

				//New mid
				const mid = String(this.transceivers.length);
				//Get media type
				const media = pending.track.getMedia();
				//Add new transceiver
				this.transceivers.push({
					mid	: mid,
					media	: media,
					remote	: {},
					local	: {
						track	: pending.track,
						stream	: pending.stream
					}
				});

			}
			//Clear pending
			this.pending.clear();
		}

		//Clean all stream stuff
		this.localInfo.removeAllStreams();

		//Check the transceivers
		for (const transceiver of this.transceivers)
		{
			//If we are sending on this transceiver
			if (transceiver.local.track)
			{
				//Get associated media info
				let mediaInfo = this.localInfo.getMediaById(transceiver.mid);
				//If there wsa none
				if (!mediaInfo)
				{
					//Clone first media of type
					mediaInfo = this.localInfo.getMedia(transceiver.media).clone();
					//Set direction
					mediaInfo.setDirection(Direction.SENDRECV);
					//Set mid
					mediaInfo.setId(transceiver.mid);
					//Add to local info
					this.localInfo.addMedia(mediaInfo);
				} else if (mediaInfo.getDirection()!==Direction.SENDRECV) {
					//Set direction
					mediaInfo.setDirection(Direction.SENDVONLY);
				}
				//Get stream info
				let streamInfo = this.localInfo.getStream(transceiver.local.stream.getId());
				//If not present yet
				if (!streamInfo)
					//Create new info
					streamInfo = new StreamInfo(transceiver.local.stream.getId());
				//Add stream to media
				this.localInfo.addStream(streamInfo);
				//Get info
				const trackInfo = transceiver.local.track.getTrackInfo();
				//Set media id
				trackInfo.setMediaId(transceiver.mid);
				//Add to stream
				streamInfo.addTrack(trackInfo);
			} else {
				//Get associated media info
				let mediaInfo = this.localInfo.getMediaById(transceiver.mid);
				//Modifiy direction
				if (mediaInfo.getDirection()===Direction.SENDRECV)
					//Set direction
					mediaInfo.setDirection(Direction.RECVONLY);
				else if (mediaInfo.getDirection()===Direction.SENDONLY)
					//Set direction
					mediaInfo.setDirection(Direction.INACTIVE);
			}
		}

		//Modify status
		switch (this.state)
		{
			case "initial":
			case "stable":
				//This is an offer
				this.state = "local-offer";
				break;
			case "remote-offer":
				this.state = "stable";
				break;
		}

		//If there re still pending
		if (this.pending.size)
			//Renegotiate again
			this.renegotiate();

		//Return sdp
		return this.localInfo.toString();
	}

	renegotiate()
	{
		//Check if we already need to renegotiate
		if (!this.renegotiationNeeded && ["initial","stable"].includes(this.state))
		{
			//Set flag
			this.renegotiationNeeded = true;
			//On next tick
			setTimeout(()=>{
				//Clean flag
				this.renegotiationNeeded = false;
				//Emit event
				this.emitter.emit("renegotiationneeded",this.transport);
			},0);
		}
	}

	processRemoteDescription(sdp)
	{
		//Parse sdp
		this.remoteInfo = SDPInfo.parse(sdp);

		//If no transport
		if (!this.transport)
		{
			//Ceate new one
			this.transport = this.endpoint.createTransport(this.remoteInfo,this.localInfo);
			//If it was an offer
			if (!this.localInfo)
				//Answer it
				this.localInfo = this.remoteInfo.answer({
					dtls		: this.transport.getLocalDTLSInfo(),
					ice		: this.transport.getLocalICEInfo(),
					candidates	: this.endpoint.getLocalCandidates(),
					capabilities	: this.capabilities
				});
			//Set RTP local properties
			this.transport.setLocalProperties(this.localInfo);
			//Set RTP remote properties
			this.transport.setRemoteProperties(this.remoteInfo);

			//Set event listeners
			this.transport.on("outgoingtrack",(track,stream)=>{
				//Add to pending
				this.pending.add({
					stream : stream,
					track  : track,
				});

				//Listen for events
				track.once("stopped", ()=>{
					//remove track and stream
					this.removed.add(track);
					//Renegotiate
					this.renegotiate();
				});

				//Renegotiate
				this.renegotiate();
			});

			// Emit event
			this.emitter.emit("transport",this.transport);
		}

		//If we need to anwser
		if (this.state!="local-offer")
			//Answer it
			this.localInfo = this.remoteInfo.answer({
				dtls		: this.transport.getLocalDTLSInfo(),
				ice		: this.transport.getLocalICEInfo(),
				candidates	: this.endpoint.getLocalCandidates(),
				capabilities	: this.capabilities
			});

		//Get all medias
		const medias = this.remoteInfo.getMedias();
		//Transceiver iterator
		let i = 0;
		//For each media
		for (const mediaInfo of this.remoteInfo.getMedias())
		{
			//Get mid
			const mid = mediaInfo.getId();
			//Get stream info
			const streamInfo = this.remoteInfo.getStreamByMediaId(mid);
			//Get associated track
			const trackInfo = this.remoteInfo.getTrackByMediaId(mid);
			//Get stream
			let stream = streamInfo ? this.transport.getIncomingStream(streamInfo.getId()) : null;
			//Get track
			let track = stream && trackInfo ? stream.getTrack(trackInfo.getId()) : null;
			//Get transceiver
			let transceiver = this.transceivers[i];
			//If there is a transceiver
			if (!transceiver)
				//Crete new one
				transceiver = this.transceivers[i] = {
					mid	: mid,
					remote	: {
						info		: mediaInfo,
					},
					local	: {
						info		:  mediaInfo.answer(this.capabilities),
					}
				};
			//Next transceiver
			i++;
			//Check new direction for remote stuff
			switch(mediaInfo.getDirection())
			{
				case Direction.SENDRECV:
				case Direction.SENDONLY:
					//If we had one nd they are different
					if (transceiver.remote.track && transceiver.remote.track!=track)
						//Stop it
						transceiver.remote.track.stop();
					//If we don't have stream
					if (!stream)
						//Create new one
						stream = this.transport.createIncomingStream(streamInfo);
					//If we don't have a track already
					else if (!track && trackInfo)
						//Create new one on the stream
						stream.createTrack(trackInfo);
					//Store track and stream info
					transceiver.remote.streamId	= stream.getId();
					transceiver.remote.track	= track;
					break;
				case Direction.RECVONLY:
				case Direction.INACTIVE:
					//if we had track
					if (track)
						//Stop it
						track.stop();
					//Delete it from transceiver
					delete (transceiver.remote.track);
					break;
			}

			//Update remote info
			transceiver.remote.info = mediaInfo;
		}

		//Modify status
		switch (this.state)
		{
			case "initial":
			case "stable":
				//This is an offer
				this.state = "remote-offer";
				break;
			case "local-offer":
				this.state = "stable";
				break;
		}

		//Return sdp
		return this.remoteInfo.toString();
	}

	stop()
	{
		//Stop transport
		if (this.transport)
			this.transport.stop();

		//Free it
		this.transport = null;
		this.endpoint = null;
	}
}

module.exports = SDPManagerUnified;
<commit_msg>Temptative fix for #128<commit_after>const SDPManager	= require("./SDPManager");

const SemanticSDP	= require("semantic-sdp");

const SDPInfo		= SemanticSDP.SDPInfo;
const Setup		= SemanticSDP.Setup;
const MediaInfo		= SemanticSDP.MediaInfo;
const CandidateInfo	= SemanticSDP.CandidateInfo;
const DTLSInfo		= SemanticSDP.DTLSInfo;
const ICEInfo		= SemanticSDP.ICEInfo;
const StreamInfo	= SemanticSDP.StreamInfo;
const TrackInfo		= SemanticSDP.TrackInfo;
const SourceGroupInfo	= SemanticSDP.SourceGroupInfo;
const Direction 	=	SemanticSDP.Direction;

class SDPManagerUnified extends SDPManager
{
	constructor(endpoint,capabilities)
	{
		//Init parent
		super();

		//Store params
		this.endpoint = endpoint;
		this.capabilities = capabilities;
		//The list of transceivers
		this.transceivers = [];
		//The pending list of local tracks not assigned to transceivers
		this.pending = new Set();
		//Set of removed local tracks
		this.removed = new Set();

		//Renegotiation needed flag
		this.renegotiationNeeded = false;

	}

	createLocalDescription()
	{
		//If there is no local info
		if (!this.localInfo)
		{
			//Create initial with
			this.localInfo = SDPInfo.create({
				dtls		: new DTLSInfo(Setup.ACTPASS,"sha-256",this.endpoint.getDTLSFingerprint()),
				ice		: ICEInfo.generate(true),
				candidates	: this.endpoint.getLocalCandidates()
			});
			//For each media capability
			for (const media of Object.keys(this.capabilities))
			{
				//New mid
				const mid = String(this.transceivers.length);
				//Create new transceiver
				const transceiver = {
					mid	: mid,
					media	: media,
					remote	: {},
					local	: {}
				};
				//Create new local media info
				const mediaInfo = transceiver.local.info = MediaInfo.create(media,this.capabilities[media]);
				//Set mid
				mediaInfo.setId(mid);
				//Add to local info
				this.localInfo.addMedia(mediaInfo);
				//Add new transceiver
				this.transceivers.push(transceiver);
			}
		}

		//First process all removed tracks
		for (const track of this.removed)
			//Check the transceivers
			for (const transceiver of this.transceivers)
				//Was it removed?
				if (transceiver.local.track == track)
				{
					//Clean transceiver
					delete(transceiver.local.track);
					delete(transceiver.local.stream);
					//Clean from removed
					this.removed.delete(track);
				}

		//Check if we can add new transceicers
		if (["initial","stable"].includes(this.state))
		{
			//For all pending transceivers
			for (const pending of this.pending)
			{
				//TODO: Check if we can reuse any empty
				/*
				 let found = false;

				for (const transceiver of this.transceivers)
				{
					 //Check new direction for local stuff
					switch(mediaInfo.getDirection())
					{
						case Direction.INACTIVE:
						case Direction.SENDONLY:
							//If we had one track on this
							if (transceiver.local.track)
								//Stop it
								transceiver.local.track.stop();
							//Delete it from transceiver
							delete (transceiver.local.track);
							break;
						case Direction.SENDRECV:
						case Direction.RECVONLY:
							//if we don't have a track and we had pending for adding
							if (!transceiver.local.track && this.pending.size)
							{
								console.log("--adding pending to transceiver mid:"+transceiver.mid + " i:"+i);
								//Get first one and remove it
								const first = this.pending.values().next();
								//Add it to the localInfo
								transceiver.local.track  = first.track;
								transceiver.local.stream = first.stream;
								//Remove from set
								this.pending.delete(first);
							}
							break;
					}
				}
				if (!found).. the following
				*/

				//New mid
				const mid = String(this.transceivers.length);
				//Get media type
				const media = pending.track.getMedia();
				//Add new transceiver
				this.transceivers.push({
					mid	: mid,
					media	: media,
					remote	: {},
					local	: {
						track	: pending.track,
						stream	: pending.stream
					}
				});

			}
			//Clear pending
			this.pending.clear();
		}

		//Clean all stream stuff
		this.localInfo.removeAllStreams();

		//Check the transceivers
		for (const transceiver of this.transceivers)
		{
			//Get associated media info
			let mediaInfo = this.localInfo.getMediaById(transceiver.mid);
			//If we are sending on this transceiver
			if (transceiver.local.track)
			{
			//If there was none
				if (!mediaInfo)
				{
					//Clone first media of type
					mediaInfo = this.localInfo.getMedia(transceiver.media).clone();
					//Set mid
					mediaInfo.setId(transceiver.mid);
					//Add to local info
					this.localInfo.addMedia(mediaInfo);
				}
				//Check if we have a remote track for this
				if (transceiver.remote.track)
					//Send and receive
					mediaInfo.setDirection(Direction.SENDRECV);
				else
					//Receive only
					mediaInfo.setDirection(Direction.SENDONLY);
				//Get stream info
				let streamInfo = this.localInfo.getStream(transceiver.local.stream.getId());
				//If not present yet
				if (!streamInfo)
					//Create new info
					streamInfo = new StreamInfo(transceiver.local.stream.getId());
				//Add stream to media
				this.localInfo.addStream(streamInfo);
				//Get info
				const trackInfo = transceiver.local.track.getTrackInfo();
				//Set media id
				trackInfo.setMediaId(transceiver.mid);
				//Add to stream
				streamInfo.addTrack(trackInfo);
			} else {
				//Check if we have a remote track for this
				if (transceiver.remote.track)
					//Receving
					mediaInfo.setDirection(Direction.RECVONLY);
				else
					//Inactive
					mediaInfo.setDirection(Direction.INACTIVE);
			}
			//Set lotal info
			transceiver.local.info = mediaInfo;
		}

		//Modify status
		switch (this.state)
		{
			case "initial":
			case "stable":
				//This is an offer
				this.state = "local-offer";
				break;
			case "remote-offer":
				this.state = "stable";
				break;
		}

		//If there re still pending
		if (this.pending.size || this.removed.size)
			//Renegotiate again
			this.renegotiate();

		//Return sdp
		return this.localInfo.toString();
	}

	renegotiate()
	{
		//Check if we already need to renegotiate
		if (!this.renegotiationNeeded && ["initial","stable"].includes(this.state))
		{
			//Set flag
			this.renegotiationNeeded = true;
			//On next tick
			setTimeout(()=>{
				//Clean flag
				this.renegotiationNeeded = false;
				//Emit event
				this.emitter.emit("renegotiationneeded",this.transport);
			},0);
		}
	}

	processRemoteDescription(sdp)
	{
		//Parse sdp
		this.remoteInfo = SDPInfo.parse(sdp);

		//Processing remote sdp
		this.processing = true;

		//If no transport
		if (!this.transport)
		{
			//Ceate new one
			this.transport = this.endpoint.createTransport(this.remoteInfo,this.localInfo);
			//If it was an offer
			if (!this.localInfo)
				//Answer it
				this.localInfo = this.remoteInfo.answer({
					dtls		: this.transport.getLocalDTLSInfo(),
					ice		: this.transport.getLocalICEInfo(),
					candidates	: this.endpoint.getLocalCandidates(),
					capabilities	: this.capabilities
				});
			//Set RTP local properties
			this.transport.setLocalProperties(this.localInfo);
			//Set RTP remote properties
			this.transport.setRemoteProperties(this.remoteInfo);

			//Set event listeners
			this.transport.on("outgoingtrack",(track,stream)=>{
				//Add to pending
				this.pending.add({
					stream : stream,
					track  : track,
				});

				//Listen for events
				track.once("stopped", ()=>{
					//remove track and stream
					this.removed.add(track);
					//If not processing remote SDP
					if (!this.processing)
						//Renegotiate
						this.renegotiate();
				});
				//If not processing remote SDP
				if (!this.processing)
					//Renegotiate
					this.renegotiate();
			});

			// Emit event
			this.emitter.emit("transport",this.transport);
		}

		//If we need to anwser
		if (this.state!="local-offer")
			//Answer it
			this.localInfo = this.remoteInfo.answer({
				dtls		: this.transport.getLocalDTLSInfo(),
				ice		: this.transport.getLocalICEInfo(),
				candidates	: this.endpoint.getLocalCandidates(),
				capabilities	: this.capabilities
			});

		//Get all medias
		const medias = this.remoteInfo.getMedias();
		//Transceiver iterator
		let i = 0;
		//For each media
		for (const mediaInfo of this.remoteInfo.getMedias())
		{
			//Get mid
			const mid = mediaInfo.getId();
			//Get stream info
			const streamInfo = this.remoteInfo.getStreamByMediaId(mid);
			//Get associated track
			const trackInfo = this.remoteInfo.getTrackByMediaId(mid);
			//Get stream
			let stream = streamInfo ? this.transport.getIncomingStream(streamInfo.getId()) : null;
			//Get track
			let track = stream && trackInfo ? stream.getTrack(trackInfo.getId()) : null;
			//Get transceiver
			let transceiver = this.transceivers[i];
			//If there is a transceiver
			if (!transceiver)
				//Crete new one
				transceiver = this.transceivers[i] = {
					mid	: mid,
					remote	: {
						info		: mediaInfo,
					},
					local	: {
						info		:  mediaInfo.answer(this.capabilities),
					}
				};
			else
				//Update media info
				transceiver.remote = mediaInfo;
			//Next transceiver
			i++;
			//Check new direction for remote stuff
			switch(mediaInfo.getDirection())
			{
				case Direction.SENDRECV:
				case Direction.SENDONLY:
					//If we had one nd they are different
					if (transceiver.remote.track && transceiver.remote.track!=track)
						//Stop it
						transceiver.remote.track.stop();
					//If we don't have stream
					if (!stream)
					{
						//Create new one
						stream = this.transport.createIncomingStream(streamInfo);
						//Get the track
						track = stream.getTrack(trackInfo.getId());
					//If we don't have a track already
					} else if (!track && trackInfo) {
						//Create new trck on the stream
						track = stream.createTrack(trackInfo);
					}
					//Store track and stream info
					transceiver.remote.streamId	= stream.getId();
					transceiver.remote.track	= track;
					break;
				case Direction.RECVONLY:
				case Direction.INACTIVE:
					//if we had track
					if (track)
						//Stop it
						track.stop();
					//Delete it from transceiver
					delete (transceiver.remote.track);
					break;
			}

			//Update remote info
			transceiver.remote.info = mediaInfo;
		}

		//Modify status
		switch (this.state)
		{
			case "initial":
			case "stable":
				//This is an offer
				this.state = "remote-offer";
				break;
			case "local-offer":
				this.state = "stable";
				break;
		}

		//Not processint SDP anymore
		this.processing = false;

		//If there re still pending
		if (this.pending.size || this.removed.size)
			//Renegotiate again
			this.renegotiate();

		//Return sdp
		return this.remoteInfo.toString();
	}

	stop()
	{
		//Stop transport
		if (this.transport)
			this.transport.stop();

		//Free it
		this.transport = null;
		this.endpoint = null;
	}
}

module.exports = SDPManagerUnified;
<|endoftext|>


<commit_before>(function(module) {
"use strict";

var mapOptions = {
  zoom: 5,
  center: new google.maps.LatLng(47.618217, -122.351832),
  mapTypeId: google.maps.MapTypeId.STREET,
  zoomControl: true,
  zoomControlOptions: {
    position: google.maps.ControlPosition.RIGHT_CENTER
  }
};

var map = new google.maps.Map(document.getElementById('map'), mapOptions);

google.maps.event.addDomListener(window, 'resize', function() {
  var center = map.getCenter();
  google.maps.event.trigger(map, 'resize');
  map.setCenter(center);
});

var marker = new google.maps.Marker({
  position: {lat: 47.618217, lng: -122.351832},
  map: map
});

// google.maps.event.addDomListener(window, 'load', function() {
//   var input = document.getElementById('id_name');
//   map.autocomplete = new google.maps.places.Autocomplete(input);
// });

$(document).ready(function() {
$.get("/api/hikes/").success(function (data) {
  console.log(data, 'data');

      // loop through places and add markers
      for (var p in data) {
        console.log(p)
        //create gmap latlng obj
        var tmpLatLng = new google.maps.LatLng( data[p].lat, data[p].lng);
        // make and place map maker.
        var marker = new google.maps.Marker({
            map: map,
            position: tmpLatLng,
            title : data[p].name
          });

      }
    })
  });

$( function() {
    $("#id_date").datepicker();
  } );

module.map = map;
})(window);<commit_msg>removed seattle marker<commit_after>(function(module) {
"use strict";

var mapOptions = {
  zoom: 5,
  center: new google.maps.LatLng(47.618217, -122.351832),
  mapTypeId: google.maps.MapTypeId.STREET,
  zoomControl: true,
  zoomControlOptions: {
    position: google.maps.ControlPosition.RIGHT_CENTER
  }
};

var map = new google.maps.Map(document.getElementById('map'), mapOptions);

google.maps.event.addDomListener(window, 'resize', function() {
  var center = map.getCenter();
  google.maps.event.trigger(map, 'resize');
  map.setCenter(center);
});

var marker = new google.maps.Marker({
  map: map
});

$(document).ready(function() {
$.get("/api/hikes/").success(function (data) {
  console.log(data, 'data');

      // loop through places and add markers
      for (var p in data) {
        console.log(p)
        //create gmap latlng obj
        var tmpLatLng = new google.maps.LatLng( data[p].lat, data[p].lng);
        // make and place map maker.
        var marker = new google.maps.Marker({
            map: map,
            position: tmpLatLng,
            title : data[p].name
          });

      }
    })
  });

module.map = map;
})(window);<|endoftext|>