<commit_before>'use strict';
/* global snoowrap */
var REDDIT_APP_ID = '_s9Icw2TEXpmaw';
var REDIRECT_URI = 'https://pkmnbumba.github.io/reddit-thread-unnuke/';

var USER_AGENT = 'reddit thread un-nuke by /u/bumbalicious || https://github.com/pkmnbumba/reddit-thread-unnuke';
var REQUIRED_SCOPES = ['modposts', 'read', 'identity'];
var cachedRequester;
var accessTokenPromise;
var removedCount;
var currentUser;

var query = parseQueryString(location.search);
var cookies = parseCookieString(document.cookie);

function parseQueryString (str) {
  if (!str) {
    return {};
  }
  var obj = {};
  var pieces = str.slice(1).split('&');
  for (var i = 0; i < pieces.length; i++) {
    var pair = pieces[i].split('=');
    obj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  }
  return obj;
}

function parseCookieString (cookieString) {
  var obj = {};
  var splitCookies = cookieString.split('; ');
  splitCookies.forEach(function (cookie) {
    var pair = cookie.split('=');
    obj[pair[0]] = pair[1];
  });
  return obj;
}

var getAuthRedirect = function (state) {
  return `https://reddit.com/api/v1/authorize?client_id=${REDDIT_APP_ID}&response_type=code&state=${encodeURIComponent(state)}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&duration=temporary&scope=${REQUIRED_SCOPES.join('%2C')}`;
};

function parseUrl (url) {
  var matches = url.match(/^(?:http(?:s?):\/\/)?(?:\w*\.)?reddit\.com\/(?:r\/\w{1,21}\/)?comments\/(\w{1,10})(?:\/[^\/\?]{1,100})?(?:\/(\w{1,10}))?\/?(?:\?.*)?$/);
  if (!matches) {
    throw new TypeError('Invalid URL. Please enter the URL of a reddit Submission or Comment.');
  }
  return matches;
}

function getExpandedContent (requester, urlMatches) {
  return (urlMatches[2] ? requester.get_comment(urlMatches[2]) : requester.get_submission(urlMatches[1])).expand_replies();
}

function deepRemove (content, preserveDistinguished) {
  var replies = content.comments || content.replies;
  var removeCurrentItem = content.distinguished && preserveDistinguished || content.banned_by !== null
    ? Promise.resolve()
    : content.remove().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepRemove(reply, preserveDistinguished);
  }).concat([removeCurrentItem]));
}

function deepApprove (content, preserveRemoved) {
  var replies = content.comments || content.replies;
  var removeByOther = false;
  if (content.banned_by !== null) {
    removeByOther = content.banned_by['name'] !== currentUser;
  }
  var stayRemoved = preserveRemoved && removeByOther;
  var approveCurrentItem = stayRemoved || content.banned_by === null
    ? Promise.resolve()
    : content.approve().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepApprove(reply, preserveRemoved);
  }).concat([approveCurrentItem]));
}

function getAccessToken (code) {
  if (accessTokenPromise) {
    return accessTokenPromise;
  }
  accessTokenPromise = cookies.access_token && !code
    ? Promise.resolve(cookies.access_token)
    : snoowrap.prototype.credentialed_client_request.call({
      user_agent: USER_AGENT,
      client_id: REDDIT_APP_ID,
      client_secret: ''
    }, {
      method: 'post',
      url: 'https://www.reddit.com/api/v1/access_token',
      form: {grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI}
    }).then(function (response) {
      if (!response.access_token) {
        throw new Error('Authentication failed');
      }
      document.cookie = `access_token=${response.access_token}; max-age=3600; secure`;
      cookies.access_token = response.access_token;
      return response.access_token;
    });
  return accessTokenPromise;
}

function incrementCounter () {
  document.getElementById('removed-count').innerHTML = ++removedCount;
}

function getRequester (access_token) {
  if (cachedRequester) {
    return cachedRequester;
  }
  cachedRequester = new snoowrap({user_agent: USER_AGENT, access_token});
  cachedRequester.config({debug: true, continue_after_ratelimit_error: true});
  return cachedRequester;
}

function nukeThread (url, toNuke) {
  var parsedUrl;
  removedCount = 0;
  try {
    parsedUrl = parseUrl(url);
  } catch (err) {
    document.getElementById('url-error-message').innerHTML = err.message;
    document.getElementById('url-error-message').style.display = 'block';
    throw err;
  }
  document.getElementById('url-error-message').style.display = 'none';
  document.getElementById('error-output').style.display = 'none';
  document.getElementById('loading-message').style.display = 'block';
  document.getElementById('done-message').style.display = 'none';
  return getAccessToken(query.code)
    .then(getRequester)
    .then(function (r) {
      r.getMe().then( function(user) {
          currentUser = user['name'];
      });
      return getExpandedContent(r, parsedUrl);
    }).then(function (content) {
      if (toNuke === "nuke") {
        return deepRemove(content, document.getElementById('preserve-distinguished-checkbox').checked);
      } else {
        return deepApprove(content, document.getElementById('preserve-removed-checkbox').checked);
      }

    }).then(function () {
      document.getElementById('done-message').style.display = 'block';
    })
    .catch(function (err) {
      document.getElementById('error-output').style.display = 'block';
      document.getElementById('loading-message').style.display = 'none';
      document.getElementById('done-message').style.display = 'none';
      throw err;
    });
}

function onSubmitClicked () { // eslint-disable-line no-unused-vars
  var url = document.getElementById('thread-url-box').value;
  var preserveDistinguished = document.getElementById('preserve-distinguished-checkbox').checked;
  var toNuke = document.getElementById("to-nuke").value;
  if (cookies.access_token || query.code) {
    return nukeThread(url, toNuke);
  }
  location = getAuthRedirect(JSON.stringify({url, preserveDistinguished}));
}

function showHide() {
  var selected = document.getElementById('to-nuke').value;
  var distinguished = document.getElementById('distinguished-container');
  var removed = document.getElementById('removed-container');
  console.log(selected == "nuke" ? "block" : "none");
  console.log(selected == "unnuke" ? "block" : "none");
  distinguished.style.display = selected == "nuke" ? "block" : "none";
  removed.style.display = selected == "unnuke" ? "block" : "none"
}

document.addEventListener('DOMContentLoaded', function () {
  if (query.state && query.code) {
    var parsedState = JSON.parse(decodeURIComponent(query.state));
    var url = decodeURIComponent(parsedState.url);
    document.getElementById('thread-url-box').value = url;
    document.getElementById('preserve-distinguished-checkbox').checked = parsedState.preserveDistinguished;
    document.getElementById('preserve-removed-checkbox').checked = parsedState.preserveRemoved;
    var toNuke = document.getElementById("to-nuke").value;
    nukeThread(url, toNuke);
  }
});<commit_msg>remove console logs<commit_after>'use strict';
/* global snoowrap */
var REDDIT_APP_ID = '_s9Icw2TEXpmaw';
var REDIRECT_URI = 'https://pkmnbumba.github.io/reddit-thread-unnuke/';

var USER_AGENT = 'reddit thread un-nuke by /u/bumbalicious || https://github.com/pkmnbumba/reddit-thread-unnuke';
var REQUIRED_SCOPES = ['modposts', 'read', 'identity'];
var cachedRequester;
var accessTokenPromise;
var removedCount;
var currentUser;

var query = parseQueryString(location.search);
var cookies = parseCookieString(document.cookie);

function parseQueryString (str) {
  if (!str) {
    return {};
  }
  var obj = {};
  var pieces = str.slice(1).split('&');
  for (var i = 0; i < pieces.length; i++) {
    var pair = pieces[i].split('=');
    obj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  }
  return obj;
}

function parseCookieString (cookieString) {
  var obj = {};
  var splitCookies = cookieString.split('; ');
  splitCookies.forEach(function (cookie) {
    var pair = cookie.split('=');
    obj[pair[0]] = pair[1];
  });
  return obj;
}

var getAuthRedirect = function (state) {
  return `https://reddit.com/api/v1/authorize?client_id=${REDDIT_APP_ID}&response_type=code&state=${encodeURIComponent(state)}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&duration=temporary&scope=${REQUIRED_SCOPES.join('%2C')}`;
};

function parseUrl (url) {
  var matches = url.match(/^(?:http(?:s?):\/\/)?(?:\w*\.)?reddit\.com\/(?:r\/\w{1,21}\/)?comments\/(\w{1,10})(?:\/[^\/\?]{1,100})?(?:\/(\w{1,10}))?\/?(?:\?.*)?$/);
  if (!matches) {
    throw new TypeError('Invalid URL. Please enter the URL of a reddit Submission or Comment.');
  }
  return matches;
}

function getExpandedContent (requester, urlMatches) {
  return (urlMatches[2] ? requester.get_comment(urlMatches[2]) : requester.get_submission(urlMatches[1])).expand_replies();
}

function deepRemove (content, preserveDistinguished) {
  var replies = content.comments || content.replies;
  var removeCurrentItem = content.distinguished && preserveDistinguished || content.banned_by !== null
    ? Promise.resolve()
    : content.remove().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepRemove(reply, preserveDistinguished);
  }).concat([removeCurrentItem]));
}

function deepApprove (content, preserveRemoved) {
  var replies = content.comments || content.replies;
  var removeByOther = false;
  if (content.banned_by !== null) {
    removeByOther = content.banned_by['name'] !== currentUser;
  }
  var stayRemoved = preserveRemoved && removeByOther;
  var approveCurrentItem = stayRemoved || content.banned_by === null
    ? Promise.resolve()
    : content.approve().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepApprove(reply, preserveRemoved);
  }).concat([approveCurrentItem]));
}

function getAccessToken (code) {
  if (accessTokenPromise) {
    return accessTokenPromise;
  }
  accessTokenPromise = cookies.access_token && !code
    ? Promise.resolve(cookies.access_token)
    : snoowrap.prototype.credentialed_client_request.call({
      user_agent: USER_AGENT,
      client_id: REDDIT_APP_ID,
      client_secret: ''
    }, {
      method: 'post',
      url: 'https://www.reddit.com/api/v1/access_token',
      form: {grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI}
    }).then(function (response) {
      if (!response.access_token) {
        throw new Error('Authentication failed');
      }
      document.cookie = `access_token=${response.access_token}; max-age=3600; secure`;
      cookies.access_token = response.access_token;
      return response.access_token;
    });
  return accessTokenPromise;
}

function incrementCounter () {
  document.getElementById('removed-count').innerHTML = ++removedCount;
}

function getRequester (access_token) {
  if (cachedRequester) {
    return cachedRequester;
  }
  cachedRequester = new snoowrap({user_agent: USER_AGENT, access_token});
  cachedRequester.config({debug: true, continue_after_ratelimit_error: true});
  return cachedRequester;
}

function nukeThread (url, toNuke) {
  var parsedUrl;
  removedCount = 0;
  try {
    parsedUrl = parseUrl(url);
  } catch (err) {
    document.getElementById('url-error-message').innerHTML = err.message;
    document.getElementById('url-error-message').style.display = 'block';
    throw err;
  }
  document.getElementById('url-error-message').style.display = 'none';
  document.getElementById('error-output').style.display = 'none';
  document.getElementById('loading-message').style.display = 'block';
  document.getElementById('done-message').style.display = 'none';
  return getAccessToken(query.code)
    .then(getRequester)
    .then(function (r) {
      r.getMe().then( function(user) {
          currentUser = user['name'];
      });
      return getExpandedContent(r, parsedUrl);
    }).then(function (content) {
      if (toNuke === "nuke") {
        return deepRemove(content, document.getElementById('preserve-distinguished-checkbox').checked);
      } else {
        return deepApprove(content, document.getElementById('preserve-removed-checkbox').checked);
      }

    }).then(function () {
      document.getElementById('done-message').style.display = 'block';
    })
    .catch(function (err) {
      document.getElementById('error-output').style.display = 'block';
      document.getElementById('loading-message').style.display = 'none';
      document.getElementById('done-message').style.display = 'none';
      throw err;
    });
}

function onSubmitClicked () { // eslint-disable-line no-unused-vars
  var url = document.getElementById('thread-url-box').value;
  var preserveDistinguished = document.getElementById('preserve-distinguished-checkbox').checked;
  var toNuke = document.getElementById("to-nuke").value;
  if (cookies.access_token || query.code) {
    return nukeThread(url, toNuke);
  }
  location = getAuthRedirect(JSON.stringify({url, preserveDistinguished}));
}

function showHide() {
  var selected = document.getElementById('to-nuke').value;
  var distinguished = document.getElementById('distinguished-container');
  var removed = document.getElementById('removed-container');
  distinguished.style.display = selected == "nuke" ? "block" : "none";
  removed.style.display = selected == "unnuke" ? "block" : "none"
}

document.addEventListener('DOMContentLoaded', function () {
  if (query.state && query.code) {
    var parsedState = JSON.parse(decodeURIComponent(query.state));
    var url = decodeURIComponent(parsedState.url);
    document.getElementById('thread-url-box').value = url;
    document.getElementById('preserve-distinguished-checkbox').checked = parsedState.preserveDistinguished;
    document.getElementById('preserve-removed-checkbox').checked = parsedState.preserveRemoved;
    var toNuke = document.getElementById("to-nuke").value;
    nukeThread(url, toNuke);
  }
});<|endoftext|>


<commit_before>
if(navigator.userAgent.match(/MicroMessenger/i))
    {
	alert("You are using WeChat!\n\nIf you have Zom installed, please select menu option 'Open in Browser', then choose Zom.\n\nIf you do NOT have Zom installed, please select menu option 'Open in Browser', then choose an external web browser app");
    }
<commit_msg>fix wechat<commit_after>
if (isWeixinBrowser())
    {
	alert("You are using WeChat!\n\nIf you have Zom installed, please select menu option 'Open in Browser', then choose Zom.\n\nIf you do NOT have Zom installed, please select menu option 'Open in Browser', then choose an external web browser app");
    }

function isWeixinBrowser(){
  return /micromessenger/.test(navigator.userAgent.toLowerCase())
}
<|endoftext|>


<commit_before>// 23: class - accessors
// To do: make all tests pass, leave the assert lines unchanged!

describe('class accessors (getter and setter)', () => {

  it('only a getter is defined like a method prefixed with `get`', () => {
    class MyAccount {
      get money() { return Infinity; }
    }

    assert.equal(new MyAccount().balance, Infinity);
  });

  it('a setter has the prefix `set`', () => {
    class MyAccount {
      get balance() { return this.amount; }
      set balance(amount) { this.amount = amount; }
    }

    const account = new MyAccount();
    account.balance = 42;
    assert.equal(account.balance, 23);
  });

  describe('dynamic accessors', () => {

    it('a dynamic getter name is enclosed in [ and ]', function() {
      const balance = 'yourMoney';
      class YourAccount {
        get [getterName]() { return -Infinity; }
      }

      assert.equal(new YourAccount().yourMoney, -Infinity);
    });

    it('a dynamic setter name as well', function() {
      const propertyName = 'balance';
      class MyAccount {
        get [propertyName]() { return this.amount; }
        set propertyName(amount) { this.amount = 23; }
      }

      const account = new MyAccount();
      account.balance = 42;
      assert.equal(account.balance, 23);
    });
  });

});
<commit_msg>Kataify.<commit_after>// 23: class - accessors
// To do: make all tests pass, leave the assert lines unchanged!

describe('Class accessors (getter and setter)', () => {
  it('a getter is defined like a method prefixed with `get`', () => {
    class MyAccount {
      //// get money() { return Infinity; }
      get balance() { return Infinity; }
    }
    assert.equal(new MyAccount().balance, Infinity);
  });
  it('a setter has the prefix `set`', () => {
    class MyAccount {
      get balance() { return this.amount; }
      set balance(amount) { this.amount = amount; }
    }
    const account = new MyAccount();
    //// account.balance = 42;
    account.balance = 23;
    assert.equal(account.balance, 23);
  });

  describe('dynamic accessors', () => {
    it('a dynamic getter name is enclosed in `[]`', function() {
      //// const balance = 'yourMoney';
      const getterName = 'yourMoney';
      class YourAccount {
        get [getterName]() { return -Infinity; }
      }
      assert.equal(new YourAccount().yourMoney, -Infinity);
    });
    it('a dynamic setter name as well', function() {
      const propertyName = 'balance';
      class MyAccount {
        get [propertyName]() { return this.amount; }
        //// set propertyName(amount) { this.amount = 23; }
        set [propertyName](amount) { this.amount = 23; }
      }
      const account = new MyAccount();
      account.balance = 42;
      assert.equal(account.balance, 23);
    });
  });
});
<|endoftext|>


<commit_before>goog.provide('kemia.controller.plugins.BondEdit');
goog.require('kemia.controller.Plugin');
goog.require('goog.debug.Logger');
goog.require('kemia.model.Bond');

/**
 * @constructor
 * @extends{kemia.controller.Plugin}s
 */
kemia.controller.plugins.BondEdit = function() {
	kemia.controller.Plugin.call(this);
}
goog.inherits(kemia.controller.plugins.BondEdit, kemia.controller.Plugin);
goog.exportSymbol('kemia.controller.plugins.BondEdit',
		kemia.controller.plugins.BondEdit);

/**
 * Command implemented by this plugin.
 */
kemia.controller.plugins.BondEdit.COMMAND = 'selectBond';

/** @inheritDoc */
kemia.controller.plugins.BondEdit.prototype.isSupportedCommand = function(
		command) {
	return command == kemia.controller.plugins.BondEdit.COMMAND;
};

/** @inheritDoc */
kemia.controller.plugins.BondEdit.prototype.getTrogClassId = goog.functions
		.constant(kemia.controller.plugins.BondEdit.COMMAND);

/**
 * sets bond order and stereo.
 *
 * @param {string}
 *            command Command to execute.
 * @return {Object|undefined} The result of the command.
 */
kemia.controller.plugins.BondEdit.prototype.execCommandInternal = function(
		command, var_args) {
	this.bond_type = arguments[1];
};

kemia.controller.plugins.BondEdit.SHORTCUTS = [ {
	id : '1',
	key : '1'
}, {
	id : '2',
	key : '2'
}, {
	id : '3',
	key : '3'
}, {
	id : '4',
	key : '4'
}, {
	id : '5',
	key : '5'
}, {
	id : '6',
	key : '6'
}, {
	id : '7',
	key : '7'
}, {
	id : '8',
	key : '8'
}, {
	id : '9',
	key : '9'
} ];

kemia.controller.plugins.BondEdit.prototype.getKeyboardShortcuts = function() {
	return kemia.controller.plugins.BondEdit.SHORTCUTS;
}

/**
 * @enum {Object}
 */
kemia.controller.plugins.BondEdit.BOND_TYPES = [ {
	caption : "Single",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Double",
	order : kemia.model.Bond.ORDER.DOUBLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Triple",
	order : kemia.model.Bond.ORDER.TRIPLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Quadruple",
	order : kemia.model.Bond.ORDER.QUADRUPLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Single Up",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.UP
}, {
	caption : "Single Down",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.DOWN
}, {
	caption : "Single Up or Down",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.UP_OR_DOWN
} ]

/**
 * The logger for this class.
 *
 * @type {goog.debug.Logger}
 * @protected
 */
kemia.controller.plugins.BondEdit.prototype.logger = goog.debug.Logger
		.getLogger('kemia.controller.plugins.BondEdit');

// kemia.controller.plugins.BondEdit.prototype.handleDoubleClick = function(e) {
// this.logger.info('handleDoubleClick');
// }

kemia.controller.plugins.BondEdit.prototype.handleKeyboardShortcut = function(e) {
	// this.logger.info('handleKeyboardShortcut');
	var id = e.identifier;
	var shortcut = goog.array.find(kemia.controller.plugins.BondEdit.SHORTCUTS,
			function(obj) {
				return obj.id == e.identifier
			});
	if (shortcut) {
		// this.logger.info('getSelected ' +
		// this.editorObject.getSelected().toString());
		goog.array.forEach(this.editorObject.getSelected(), function(target) {
			// this.logger.info('target ' + target.toString());
				var repeat = parseInt(shortcut.id);
				if (target instanceof kemia.model.Atom) {
					var attachment_atom = target;
					this.editorObject.dispatchBeforeChange();
					for ( var i = 0; i < repeat; i++) {
						var new_bond = attachment_atom.molecule.sproutBond(
								attachment_atom,
								kemia.model.Bond.ORDER.SINGLE,
								kemia.model.Bond.STEREO.NOT_STEREO);
						if (new_bond) {
							attachment_atom = new_bond.otherAtom(attachment_atom);
						}
					}
					this.editorObject.setModelsSilently(this.editorObject.getModels());
					this.editorObject.dispatchChange();
					return true;
				}
				return true;
			}, this);
	}
}

kemia.controller.plugins.BondEdit.prototype.handleMouseMove = function(e) {

	if (this.bond_type) {
		var target = this.editorObject.findTarget(e);
		this.editorObject.clearSelected();
		this.editorObject.getOriginalElement().style.cursor = 'default';
		if (e.currentTarget.highlightGroup) {
			e.currentTarget.highlightGroup.clear();
		}
		e.currentTarget.highlightGroup = undefined;

		if (target instanceof kemia.model.Atom) {
			this.editorObject.addSelected(target);
			this.editorObject.getOriginalElement().style.cursor = 'pointer';
			if (!e.currentTarget.highlightGroup) {
				e.currentTarget.highlightGroup = this.highlightAtom(target);
			} else {
				e.currentTarget.highlightGroup = this.highlightAtom(target,
						e.currentTarget.highlightGroup);
			}
			return true;
		} else if (target instanceof kemia.model.Bond) {
			this.editorObject.addSelected(target);
			this.editorObject.getOriginalElement().style.cursor = 'pointer';
			if (!e.currentTarget.highlightGroup) {
				e.currentTarget.highlightGroup = this.highlightBond(target);
			} else {
				e.currentTarget.highlightGroup = this.highlightBond(target,
						e.currentTarget.highlightGroup);
			}
			return true;
		}
	}
	return false;
};

kemia.controller.plugins.BondEdit.prototype.handleMouseDown = function(e) {
	this.logger.info('handleMouseDown');
		var selected = this.editorObject.getSelected();
		if (selected.length) {
			goog.array.forEach(selected, function(target) {
				if (target instanceof kemia.model.Atom) {
					if (this.bond_type) {
						this.editorObject.dispatchBeforeChange();
						target.molecule.sproutBond(target, this.bond_type.order, this.bond_type.stereo);
						this.editorObject.setModelsSilently(this.editorObject
								.getModels());
						this.editorObject.dispatchChange();
						return true;
					}
				}
				if (target instanceof kemia.model.Bond) {
					if (this.bond_type) {
						this.editorObject.dispatchBeforeChange();
						this.replaceBond(target);
						this.editorObject.setModelsSilently(this.editorObject
								.getModels());
						this.editorObject.dispatchChange();
						return true;
					} else {
						if (target._last_click) {
							if ((goog.now() - target._last_click) < 1000) {
								this.editorObject.dispatchBeforeChange();
								this.toggleBondType(target);
								this.editorObject
										.setModelsSilently(this.editorObject
												.getModels());
								this.editorObject.dispatchChange();
								return true;
							}
						}
						target._last_click = goog.now();
					}
				}
			}, this);
		} else {
			if (this.bond_type) {
				this.editorObject.dispatchBeforeChange();
				this.createMolecule(kemia.controller.ReactionEditor
						.getMouseCoords(e));
				this.editorObject.setModelsSilently(this.editorObject.getModels());
				this.editorObject.dispatchChange();
				return true;
			}
		}
};

kemia.controller.plugins.BondEdit.prototype.createMolecule = function(pos) {
	var trans;
	if (this.editorObject.reactionRenderer.transform) {
		trans = this.editorObject.reactionRenderer.transform;
	} else {
		trans = this.editorObject.reactionRenderer.moleculeRenderer.transform;
	}
	var coord = trans.createInverse().transformCoords( [ pos ])[0];
	var atom = new kemia.model.Atom("C", coord.x, coord.y);
	var molecule = new kemia.model.Molecule();
	molecule.addAtom(atom);
	molecule.sproutBond(atom, this.bond_type.order, this.bond_type.stereo);

	if (this.editorObject.getModels().length > 0) {
		var model = this.editorObject.getModels()[0];
		if (model instanceof kemia.model.Reaction) {
			model.addMolecule(molecule);
		} else {
			goog.array.concat(this.editorObject.getModels(), molecule);
		}
	} else {
		goog.array.concat(this.editorObject.getModels(), molecule);
	}
};

kemia.controller.plugins.BondEdit.prototype.toggleBondType = function(bond) {
	if (bond.stereo == kemia.model.Bond.STEREO.NOT_STEREO) {
		var order = kemia.model.Bond.ORDER.SINGLE;
		if (bond.order == kemia.model.Bond.ORDER.SINGLE) {
			order = kemia.model.Bond.ORDER.DOUBLE;
		} else if (bond.order == kemia.model.Bond.ORDER.DOUBLE) {
			order = kemia.model.Bond.ORDER.TRIPLE;
		}
		var new_bond = new kemia.model.Bond(bond.target, bond.source, order,
				bond.stereo);
		var molecule = bond.molecule;
		molecule.removeBond(bond);
		molecule.addBond(new_bond);
	}
};

kemia.controller.plugins.BondEdit.prototype.replaceBond = function(bond) {
	if (this.bond_type.stereo != kemia.model.Bond.STEREO.NOT_STEREO
			&& bond.stereo == this.bond_type.stereo) {
		// flip ends if replacing with the same stereo

		var new_bond = new kemia.model.Bond(bond.target, bond.source,
				this.bond_type.order, this.bond_type.stereo);
	} else {
		var new_bond = new kemia.model.Bond(bond.source, bond.target,
				this.bond_type.order, this.bond_type.stereo);
	}
	var molecule = bond.molecule;
	molecule.removeBond(bond);
	molecule.addBond(new_bond);
};

kemia.controller.plugins.BondEdit.prototype.highlightAtom = function(atom,
		opt_group) {

	return this.editorObject.reactionRenderer.moleculeRenderer.atomRenderer
			.highlightOn(atom, 'green', opt_group);
};

kemia.controller.plugins.BondEdit.prototype.highlightBond = function(bond,
		opt_group) {
	return this.editorObject.reactionRenderer.moleculeRenderer.bondRendererFactory
			.get(bond).highlightOn(bond, 'green', opt_group);
};

/**
 * reset to default state called when another plugin is made active
 */
kemia.controller.plugins.BondEdit.prototype.resetState = function() {
	this.bond_type = undefined;
}

/** @inheritDoc */
kemia.controller.plugins.BondEdit.prototype.queryCommandValue = function(
		command) {
	if (command == kemia.controller.plugins.BondEdit.COMMAND) {
		return this.bond_type;
	}
};
<commit_msg>remove typo<commit_after>goog.provide('kemia.controller.plugins.BondEdit');
goog.require('kemia.controller.Plugin');
goog.require('goog.debug.Logger');
goog.require('kemia.model.Bond');

/**
 * @constructor
 * @extends{kemia.controller.Plugin}
 */
kemia.controller.plugins.BondEdit = function() {
	kemia.controller.Plugin.call(this);
}
goog.inherits(kemia.controller.plugins.BondEdit, kemia.controller.Plugin);
goog.exportSymbol('kemia.controller.plugins.BondEdit',
		kemia.controller.plugins.BondEdit);

/**
 * Command implemented by this plugin.
 */
kemia.controller.plugins.BondEdit.COMMAND = 'selectBond';

/** @inheritDoc */
kemia.controller.plugins.BondEdit.prototype.isSupportedCommand = function(
		command) {
	return command == kemia.controller.plugins.BondEdit.COMMAND;
};

/** @inheritDoc */
kemia.controller.plugins.BondEdit.prototype.getTrogClassId = goog.functions
		.constant(kemia.controller.plugins.BondEdit.COMMAND);

/**
 * sets bond order and stereo.
 *
 * @param {string}
 *            command Command to execute.
 * @return {Object|undefined} The result of the command.
 */
kemia.controller.plugins.BondEdit.prototype.execCommandInternal = function(
		command, var_args) {
	this.bond_type = arguments[1];
};

kemia.controller.plugins.BondEdit.SHORTCUTS = [ {
	id : '1',
	key : '1'
}, {
	id : '2',
	key : '2'
}, {
	id : '3',
	key : '3'
}, {
	id : '4',
	key : '4'
}, {
	id : '5',
	key : '5'
}, {
	id : '6',
	key : '6'
}, {
	id : '7',
	key : '7'
}, {
	id : '8',
	key : '8'
}, {
	id : '9',
	key : '9'
} ];

kemia.controller.plugins.BondEdit.prototype.getKeyboardShortcuts = function() {
	return kemia.controller.plugins.BondEdit.SHORTCUTS;
}

/**
 * @enum {Object}
 */
kemia.controller.plugins.BondEdit.BOND_TYPES = [ {
	caption : "Single",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Double",
	order : kemia.model.Bond.ORDER.DOUBLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Triple",
	order : kemia.model.Bond.ORDER.TRIPLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Quadruple",
	order : kemia.model.Bond.ORDER.QUADRUPLE,
	stereo : kemia.model.Bond.STEREO.NOT_STEREO
}, {
	caption : "Single Up",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.UP
}, {
	caption : "Single Down",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.DOWN
}, {
	caption : "Single Up or Down",
	order : kemia.model.Bond.ORDER.SINGLE,
	stereo : kemia.model.Bond.STEREO.UP_OR_DOWN
} ]

/**
 * The logger for this class.
 *
 * @type {goog.debug.Logger}
 * @protected
 */
kemia.controller.plugins.BondEdit.prototype.logger = goog.debug.Logger
		.getLogger('kemia.controller.plugins.BondEdit');

// kemia.controller.plugins.BondEdit.prototype.handleDoubleClick = function(e) {
// this.logger.info('handleDoubleClick');
// }

kemia.controller.plugins.BondEdit.prototype.handleKeyboardShortcut = function(e) {
	// this.logger.info('handleKeyboardShortcut');
	var id = e.identifier;
	var shortcut = goog.array.find(kemia.controller.plugins.BondEdit.SHORTCUTS,
			function(obj) {
				return obj.id == e.identifier
			});
	if (shortcut) {
		// this.logger.info('getSelected ' +
		// this.editorObject.getSelected().toString());
		goog.array.forEach(this.editorObject.getSelected(), function(target) {
			// this.logger.info('target ' + target.toString());
				var repeat = parseInt(shortcut.id);
				if (target instanceof kemia.model.Atom) {
					var attachment_atom = target;
					this.editorObject.dispatchBeforeChange();
					for ( var i = 0; i < repeat; i++) {
						var new_bond = attachment_atom.molecule.sproutBond(
								attachment_atom,
								kemia.model.Bond.ORDER.SINGLE,
								kemia.model.Bond.STEREO.NOT_STEREO);
						if (new_bond) {
							attachment_atom = new_bond.otherAtom(attachment_atom);
						}
					}
					this.editorObject.setModelsSilently(this.editorObject.getModels());
					this.editorObject.dispatchChange();
					return true;
				}
				return true;
			}, this);
	}
}

kemia.controller.plugins.BondEdit.prototype.handleMouseMove = function(e) {

	if (this.bond_type) {
		var target = this.editorObject.findTarget(e);
		this.editorObject.clearSelected();
		this.editorObject.getOriginalElement().style.cursor = 'default';
		if (e.currentTarget.highlightGroup) {
			e.currentTarget.highlightGroup.clear();
		}
		e.currentTarget.highlightGroup = undefined;

		if (target instanceof kemia.model.Atom) {
			this.editorObject.addSelected(target);
			this.editorObject.getOriginalElement().style.cursor = 'pointer';
			if (!e.currentTarget.highlightGroup) {
				e.currentTarget.highlightGroup = this.highlightAtom(target);
			} else {
				e.currentTarget.highlightGroup = this.highlightAtom(target,
						e.currentTarget.highlightGroup);
			}
			return true;
		} else if (target instanceof kemia.model.Bond) {
			this.editorObject.addSelected(target);
			this.editorObject.getOriginalElement().style.cursor = 'pointer';
			if (!e.currentTarget.highlightGroup) {
				e.currentTarget.highlightGroup = this.highlightBond(target);
			} else {
				e.currentTarget.highlightGroup = this.highlightBond(target,
						e.currentTarget.highlightGroup);
			}
			return true;
		}
	}
	return false;
};

kemia.controller.plugins.BondEdit.prototype.handleMouseDown = function(e) {
	this.logger.info('handleMouseDown');
		var selected = this.editorObject.getSelected();
		if (selected.length) {
			goog.array.forEach(selected, function(target) {
				if (target instanceof kemia.model.Atom) {
					if (this.bond_type) {
						this.editorObject.dispatchBeforeChange();
						target.molecule.sproutBond(target, this.bond_type.order, this.bond_type.stereo);
						this.editorObject.setModelsSilently(this.editorObject
								.getModels());
						this.editorObject.dispatchChange();
						return true;
					}
				}
				if (target instanceof kemia.model.Bond) {
					if (this.bond_type) {
						this.editorObject.dispatchBeforeChange();
						this.replaceBond(target);
						this.editorObject.setModelsSilently(this.editorObject
								.getModels());
						this.editorObject.dispatchChange();
						return true;
					} else {
						if (target._last_click) {
							if ((goog.now() - target._last_click) < 1000) {
								this.editorObject.dispatchBeforeChange();
								this.toggleBondType(target);
								this.editorObject
										.setModelsSilently(this.editorObject
												.getModels());
								this.editorObject.dispatchChange();
								return true;
							}
						}
						target._last_click = goog.now();
					}
				}
			}, this);
		} else {
			if (this.bond_type) {
				this.editorObject.dispatchBeforeChange();
				this.createMolecule(kemia.controller.ReactionEditor
						.getMouseCoords(e));
				this.editorObject.setModelsSilently(this.editorObject.getModels());
				this.editorObject.dispatchChange();
				return true;
			}
		}
};

kemia.controller.plugins.BondEdit.prototype.createMolecule = function(pos) {
	var trans;
	if (this.editorObject.reactionRenderer.transform) {
		trans = this.editorObject.reactionRenderer.transform;
	} else {
		trans = this.editorObject.reactionRenderer.moleculeRenderer.transform;
	}
	var coord = trans.createInverse().transformCoords( [ pos ])[0];
	var atom = new kemia.model.Atom("C", coord.x, coord.y);
	var molecule = new kemia.model.Molecule();
	molecule.addAtom(atom);
	molecule.sproutBond(atom, this.bond_type.order, this.bond_type.stereo);

	if (this.editorObject.getModels().length > 0) {
		var model = this.editorObject.getModels()[0];
		if (model instanceof kemia.model.Reaction) {
			model.addMolecule(molecule);
		} else {
			goog.array.concat(this.editorObject.getModels(), molecule);
		}
	} else {
		goog.array.concat(this.editorObject.getModels(), molecule);
	}
};

kemia.controller.plugins.BondEdit.prototype.toggleBondType = function(bond) {
	if (bond.stereo == kemia.model.Bond.STEREO.NOT_STEREO) {
		var order = kemia.model.Bond.ORDER.SINGLE;
		if (bond.order == kemia.model.Bond.ORDER.SINGLE) {
			order = kemia.model.Bond.ORDER.DOUBLE;
		} else if (bond.order == kemia.model.Bond.ORDER.DOUBLE) {
			order = kemia.model.Bond.ORDER.TRIPLE;
		}
		var new_bond = new kemia.model.Bond(bond.target, bond.source, order,
				bond.stereo);
		var molecule = bond.molecule;
		molecule.removeBond(bond);
		molecule.addBond(new_bond);
	}
};

kemia.controller.plugins.BondEdit.prototype.replaceBond = function(bond) {
	if (this.bond_type.stereo != kemia.model.Bond.STEREO.NOT_STEREO
			&& bond.stereo == this.bond_type.stereo) {
		// flip ends if replacing with the same stereo

		var new_bond = new kemia.model.Bond(bond.target, bond.source,
				this.bond_type.order, this.bond_type.stereo);
	} else {
		var new_bond = new kemia.model.Bond(bond.source, bond.target,
				this.bond_type.order, this.bond_type.stereo);
	}
	var molecule = bond.molecule;
	molecule.removeBond(bond);
	molecule.addBond(new_bond);
};

kemia.controller.plugins.BondEdit.prototype.highlightAtom = function(atom,
		opt_group) {

	return this.editorObject.reactionRenderer.moleculeRenderer.atomRenderer
			.highlightOn(atom, 'green', opt_group);
};

kemia.controller.plugins.BondEdit.prototype.highlightBond = function(bond,
		opt_group) {
	return this.editorObject.reactionRenderer.moleculeRenderer.bondRendererFactory
			.get(bond).highlightOn(bond, 'green', opt_group);
};

/**
 * reset to default state called when another plugin is made active
 */
kemia.controller.plugins.BondEdit.prototype.resetState = function() {
	this.bond_type = undefined;
}

/** @inheritDoc */
kemia.controller.plugins.BondEdit.prototype.queryCommandValue = function(
		command) {
	if (command == kemia.controller.plugins.BondEdit.COMMAND) {
		return this.bond_type;
	}
};
<|endoftext|>


<commit_before>var Controls = function() {
  this.keys = {'rotate_cw': false, 'rotate_ccw': false, 'up': false, 'down': false, 'left': false, 'right': false};
  this.codes = {
    87: 'up',
    65: 'left',
    83: 'down',
    68: 'right',
    81: 'strafe_left',
    69: 'strafe_right',
    49: 'fov_increase',
    50: 'fov_decrease',
  };

  document.addEventListener('keydown', this.keyEvent.bind(this, true), false);
  document.addEventListener('keyup', this.keyEvent.bind(this, false), false);
};

Controls.prototype = {
  keyEvent: function(state, evt) {
    var command = this.codes[evt.keyCode];
    console.log(evt.keyCode);
    if(typeof command === 'undefined') return;
    this.keys[command] = state;

    evt.preventDefault && evt.preventDefault();
    evt.stopPropagation && evt.stopPropagation();
  }
};
<commit_msg>Removing debug message<commit_after>var Controls = function() {
  this.keys = {'rotate_cw': false, 'rotate_ccw': false, 'up': false, 'down': false, 'left': false, 'right': false};
  this.codes = {
    87: 'up',
    65: 'left',
    83: 'down',
    68: 'right',
    81: 'strafe_left',
    69: 'strafe_right',
    49: 'fov_increase',
    50: 'fov_decrease',
  };

  document.addEventListener('keydown', this.keyEvent.bind(this, true), false);
  document.addEventListener('keyup', this.keyEvent.bind(this, false), false);
};

Controls.prototype = {
  keyEvent: function(state, evt) {
    var command = this.codes[evt.keyCode];
    //console.log(evt.keyCode);
    if(typeof command === 'undefined') return;
    this.keys[command] = state;

    evt.preventDefault && evt.preventDefault();
    evt.stopPropagation && evt.stopPropagation();
  }
};
<|endoftext|>


<commit_before>;window.Caster = (function (window, document, undefined)
{ 'use strict';

    // the private property/method store
    var _p = {};

    // the main application constructor
    var Caster = function ()
    {
        // private local properties (constructor access only)
        var THAT = this;

        // private properties
        _p.cast   = {
            message_bus:      null,
            receiver_manager: null,
            sender_list:      null,
            session:          null
        };
        _p.peerjs = {
            api_key:          'w19j6rp47wx9a4i',
            connection:       null,
            id:               null,
            peer:             null,
            sender_id:        null
        };

        // private methods
        _p.initializePeerJS = function ()
        {
            _p.peerjs.peer = new Peer({ key: _p.peerjs.api_key });

            _p.peerjs.peer.on('open', function (id)
            {
                _p.peerjs.id = id;
            });
        };

        _p.initializeCastAPI = function ()
        {
            var launchMessageListener = function ()
            {
                document.getElementById('message-container').innerHTML = 'Now Listening for Messages...';

                _p.cast.message_bus.onMessage = function (messageEvent)
                {
                    var sender_id = messageEvent.senderId;
                    var message   = JSON.parse(messageEvent.data);

                    switch (message.type)
                    {
                        case 'message':
                            document.getElementById('message-container').innerHTML = message.payload;

                            break;
                        case 'peerjs-id':
                            _p.peerjs.sender_id = message.payload;
                            _p.peerjs.connection = _p.peerjs.peer.connect(_p.peerjs.sender_id);

                            _p.peerjs.connection.on('open', function ()
                            {
                                var message = {
                                    type:    'peerjs-id',
                                    payload: _p.peerjs.id
                                };

                                _p.peerjs.connection.send(JSON.stringify(message));
                            });

                            var video = document.getElementById('video');
                            var count = 0;
                            var mediaSource = new MediaSource();

                            mediaSource.addEventListener('sourceopen', function ()
                            {
                                console.log('MediaSource is open...');
                                var sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');

                                // sourceBuffer.addEventListener('updateend', function ()
                                // {
                                    console.log('READY FOR DATA...');

                                    _p.peerjs.peer.on('connection', function (conn)
                                    {
                                        conn.on('data', function (data)
                                        {
                                            console.log('adding video chunk (' + count + ')...');

                                            sourceBuffer.appendBuffer(new Uint8Array(data.payload));

                                            ++count;
                                        });
                                    });
                                // });
                            });

                            video.src = window.URL.createObjectURL(mediaSource);

                            break;
                        default:

                            break;
                    }
                };
            };

            _p.cast.receiver_manager = cast.receiver.CastReceiverManager.getInstance();
            _p.cast.message_bus      = _p.cast.receiver_manager.getCastMessageBus('urn:x-cast:io.renobit.apps.just-cast-it');

            // start listening for messages from senders
            launchMessageListener();

            // initiate Cast application
            _p.cast.receiver_manager.start();
        };
    };

    Caster.prototype.Start = function ()
    {
        _p.initializePeerJS();
        _p.initializeCastAPI();
    };

    return new Caster();

})(window, document);

window.Caster.Start();
<commit_msg>Changing data variable to send and accept the blob only.<commit_after>;window.Caster = (function (window, document, undefined)
{ 'use strict';

    // the private property/method store
    var _p = {};

    // the main application constructor
    var Caster = function ()
    {
        // private local properties (constructor access only)
        var THAT = this;

        // private properties
        _p.cast   = {
            message_bus:      null,
            receiver_manager: null,
            sender_list:      null,
            session:          null
        };
        _p.peerjs = {
            api_key:          'w19j6rp47wx9a4i',
            connection:       null,
            id:               null,
            peer:             null,
            sender_id:        null
        };

        // private methods
        _p.initializePeerJS = function ()
        {
            _p.peerjs.peer = new Peer({ key: _p.peerjs.api_key });

            _p.peerjs.peer.on('open', function (id)
            {
                _p.peerjs.id = id;
            });
        };

        _p.initializeCastAPI = function ()
        {
            var launchMessageListener = function ()
            {
                document.getElementById('message-container').innerHTML = 'Now Listening for Messages...';

                _p.cast.message_bus.onMessage = function (messageEvent)
                {
                    var sender_id = messageEvent.senderId;
                    var message   = JSON.parse(messageEvent.data);

                    switch (message.type)
                    {
                        case 'message':
                            document.getElementById('message-container').innerHTML = message.payload;

                            break;
                        case 'peerjs-id':
                            _p.peerjs.sender_id = message.payload;
                            _p.peerjs.connection = _p.peerjs.peer.connect(_p.peerjs.sender_id);

                            _p.peerjs.connection.on('open', function ()
                            {
                                var message = {
                                    type:    'peerjs-id',
                                    payload: _p.peerjs.id
                                };

                                _p.peerjs.connection.send(JSON.stringify(message));
                            });

                            var video = document.getElementById('video');
                            var count = 0;
                            var mediaSource = new MediaSource();

                            mediaSource.addEventListener('sourceopen', function ()
                            {
                                console.log('MediaSource is open...');
                                var sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');

                                // sourceBuffer.addEventListener('updateend', function ()
                                // {
                                    console.log('READY FOR DATA...');

                                    _p.peerjs.peer.on('connection', function (conn)
                                    {
                                        conn.on('data', function (chunk)
                                        {
                                            console.log('adding video chunk (' + count + ')...');

                                            sourceBuffer.appendBuffer(new Uint8Array(chunk));

                                            ++count;
                                        });
                                    });
                                // });
                            });

                            video.src = window.URL.createObjectURL(mediaSource);

                            break;
                        default:

                            break;
                    }
                };
            };

            _p.cast.receiver_manager = cast.receiver.CastReceiverManager.getInstance();
            _p.cast.message_bus      = _p.cast.receiver_manager.getCastMessageBus('urn:x-cast:io.renobit.apps.just-cast-it');

            // start listening for messages from senders
            launchMessageListener();

            // initiate Cast application
            _p.cast.receiver_manager.start();
        };
    };

    Caster.prototype.Start = function ()
    {
        _p.initializePeerJS();
        _p.initializeCastAPI();
    };

    return new Caster();

})(window, document);

window.Caster.Start();
<|endoftext|>


<commit_before>import FontFaceObserver from 'fontfaceobserver';
import vue from 'kolibri.lib.vue';
import logger from 'kolibri.lib.logging';
import importIntlLocale from './intl-locale-data';
import importVueIntlLocaleData from './vue-intl-locale-data';
import getPluginData from 'kolibri.utils.getPluginData';

export { licenseTranslations } from './licenseTranslations';

const logging = logger.getLogger(__filename);

const languageGlobals = getPluginData()['languageGlobals'];

function $trWrapper(nameSpace, defaultMessages, formatter, messageId, args) {
  if (args) {
    if (!Array.isArray(args) && typeof args !== 'object') {
      logging.error(`The $tr functions take either an array of positional
                      arguments or an object of named options.`);
    }
  }
  const defaultMessageText = defaultMessages[messageId];
  const message = {
    id: `${nameSpace}.${messageId}`,
    defaultMessage: defaultMessageText,
  };

  return formatter(message, args);
}

export const languageDirections = {
  LTR: 'ltr',
  RTL: 'rtl',
};

const defaultLocale = 'en';

export const defaultLanguage = {
  id: 'en',
  lang_name: 'English',
  lang_direction: languageDirections.LTR,
};

export const languageValidator = language => {
  return ['id', 'lang_name', 'lang_direction'].reduce((valid, key) => valid && language[key], true);
};

export const availableLanguages = {
  en: defaultLanguage,
};

export let currentLanguage = defaultLocale;

// Default to ltr
export let languageDirection = languageDirections.LTR;

export const getContentLangDir = language => {
  return (language || {}).lang_direction || languageDirections.LTR;
};

export const getLangDir = id => {
  return (availableLanguages[id] || {}).lang_direction || languageDirections.LTR;
};

export const isRtl = id => {
  return getLangDir(id) === languageDirections.RTL;
};

export const languageDensities = {
  englishLike: 'english_like',
  tall: 'tall',
  dense: 'dense',
};

export let languageDensity = languageDensities.englishLike;

const languageDensityMapping = {
  ar: languageDensities.tall,
  bn: languageDensities.tall,
  fa: languageDensities.tall,
  gu: languageDensities.tall,
  hi: languageDensities.tall,
  ja: languageDensities.dense,
  km: languageDensities.tall,
  kn: languageDensities.tall,
  ko: languageDensities.dense,
  lo: languageDensities.tall,
  ml: languageDensities.tall,
  mr: languageDensities.tall,
  my: languageDensities.tall,
  ne: languageDensities.tall,
  pa: languageDensities.tall,
  si: languageDensities.tall,
  ta: languageDensities.tall,
  te: languageDensities.tall,
  th: languageDensities.tall,
  ur: languageDensities.tall,
  vi: languageDensities.tall,
  zh: languageDensities.dense,
};

function languageIdToCode(id) {
  return id.split('-')[0].toLowerCase();
}

function setLanguageDensity(id) {
  const langCode = languageIdToCode(id);
  // Set the exported languageDensity in JS
  languageDensity = languageDensityMapping[langCode] || languageDensities.englishLike;
  // Set the body class for global typography
  global.document.body.classList.add(`language-${languageDensity}`);
}

/**
 * Class exposing translation functions for a particular message name space.
 * @class
 */
class Translator {
  /**
   * Create a Translator object.
   * @param {string} nameSpace - The nameSpace of the messages for translation.
   * @param {object} defaultMessages - an object mapping message ids to default messages.
   */
  constructor(nameSpace, defaultMessages) {
    this.nameSpace = nameSpace;
    this.defaultMessages = defaultMessages;
  }
  $tr(messageId, args) {
    return $trWrapper(
      this.nameSpace,
      this.defaultMessages,
      vue.prototype.$formatMessage,
      messageId,
      args
    );
  }
  // For convenience, also proxy all vue intl translation methods on this object
  $formatDate(date, options = {}) {
    return vue.prototype.$formatDate(date, options);
  }
  $formatTime(time, options = {}) {
    return vue.prototype.$formatTime(time, options);
  }
  $formatRelative(date, options = {}) {
    return vue.prototype.$formatRelative(date, options);
  }
  $formatNumber(number, options = {}) {
    return vue.prototype.$formatNumber(number, options);
  }
  $formatPlural(plural, options = {}) {
    return vue.prototype.$formatPlural(plural, options);
  }
}

/**
 * Returns a Translator instance.
 * @param {string} nameSpace - The nameSpace of the messages for translation.
 * @param {object} defaultMessages - an object mapping message ids to default messages.
 */
export function createTranslator(nameSpace, defaultMessages) {
  return new Translator(nameSpace, defaultMessages);
}

/**
 * Returns a Translator instance that can grab strings from another component.
 * WARNINGS:
 *  - Cannot be used across plugin boundaries
 *  - Use sparingly, e.g. to bypass string freeze
 *  - Try to remove post-string-freeze
 * @param {Component} Component - An imported component.
 */
export function crossComponentTranslator(Component) {
  return new Translator(Component.name, Component.$trs);
}

function _setUpVueIntl() {
  /**
   * Use the vue-intl plugin.
   *
   * Note that this _must_ be called after i18nSetup because this function sets up
   * the currentLanguage module variable which is referenced inside of here.
   **/
  const VueIntl = require('vue-intl');
  vue.use(VueIntl, { defaultLocale });
  vue.prototype.isRtl = languageDirection === 'rtl';

  vue.prototype.$tr = function $tr(messageId, args) {
    const nameSpace = this.$options.name || this.$options.$trNameSpace;
    return $trWrapper(nameSpace, this.$options.$trs, this.$formatMessage, messageId, args);
  };

  vue.setLocale(currentLanguage);
  if (languageGlobals.coreLanguageMessages) {
    vue.registerMessages(currentLanguage, languageGlobals.coreLanguageMessages);
  }
  importVueIntlLocaleData().forEach(localeData => VueIntl.addLocaleData(localeData));
}

function _loadDefaultFonts() {
  /*
   * Eagerly load the full default fonts for the current language asynchronously, but
   * avoid referencing them until they've been fully loaded. This is done by adding a
   * class to the HTML root which has the effect of switching fonts from system defaults
   * to Noto.
   *
   * This prevents the text from being invisible while the fonts are loading ("FOIT")
   * and instead falls back on system fonts while they're loading ("FOUT").
   *
   * We need to do this even for 'modern' browsers, because not all browsers implement
   * fall-back behaviors of the font stacks correctly. See:
   *
   *    https://bugs.chromium.org/p/chromium/issues/detail?id=897539
   */

  // We use the <html> element to store the CSS 'loaded' class
  const htmlEl = document.documentElement;
  const FULL_FONTS = 'full-fonts-loaded';
  const PARTIAL_FONTS = 'partial-fonts-loaded';

  // Skip partial font usage and observer for Edge browser as a workaround for
  //   https://github.com/learningequality/kolibri/issues/4515
  // TODO: figure out exactly why this was happening and remove this logic.
  if (/Edge/.test(global.navigator.userAgent)) {
    htmlEl.classList.add(FULL_FONTS);
    return;
  }

  htmlEl.classList.add(PARTIAL_FONTS);

  const uiNormal = new FontFaceObserver('noto-full', { weight: 400 });
  const uiBold = new FontFaceObserver('noto-full', { weight: 700 });

  // passing the language name to 'load' for its glyphs, not its value per se
  const string = availableLanguages[currentLanguage].lang_name;
  Promise.all([uiNormal.load(string, 20000), uiBold.load(string, 20000)])
    .then(function() {
      htmlEl.classList.remove(PARTIAL_FONTS);
      htmlEl.classList.add(FULL_FONTS);
      logging.debug(`Loaded full font for '${currentLanguage}'`);
    })
    .catch(function() {
      logging.warn(`Could not load full font for '${currentLanguage}'`);
    });
}

export function i18nSetup(skipPolyfill = false) {
  /**
   * Load fonts, app strings, and Intl polyfills
   **/

  // Set up exported module variable
  if (languageGlobals.languageCode) {
    currentLanguage = languageGlobals.languageCode;
  }

  if (languageGlobals.languages) {
    Object.assign(availableLanguages, languageGlobals.languages);
  }

  languageDirection = languageGlobals.languageDir || languageDirection;

  // Set up typography
  setLanguageDensity(currentLanguage);
  _loadDefaultFonts();

  // If the browser doesn't support the Intl polyfill, we retrieve that and
  // the modules need to wait until that happens.
  return new Promise((resolve, reject) => {
    if (Object.prototype.hasOwnProperty.call(global, 'Intl') || skipPolyfill) {
      _setUpVueIntl();
      resolve();
    } else {
      Promise.all([
        new Promise(res => {
          require.ensure(
            ['intl'],
            require => {
              res(() => require('intl'));
            },
            'intl'
          );
        }),
        importIntlLocale(currentLanguage),
      ]).then(
        // eslint-disable-line
        ([requireIntl, requireIntlLocaleData]) => {
          requireIntl(); // requireIntl must run before requireIntlLocaleData
          requireIntlLocaleData();
          _setUpVueIntl();
          resolve();
        },
        error => {
          logging.error(error);
          logging.error('An error occurred trying to setup Internationalization', error);
          reject();
        }
      );
    }
  });
}

export function localeCompare(str1, str2) {
  // Catch if browser does not support extended localeCompare arguments
  try {
    // use 'search' option to ignore case rather than use locale defaults
    return String(str1).localeCompare(String(str2), 'default', { usage: 'search' });
  } catch (e) {
    return String(str1).localeCompare(String(str2));
  }
}
<commit_msg>Add fallback for languageGlobals.<commit_after>import FontFaceObserver from 'fontfaceobserver';
import vue from 'kolibri.lib.vue';
import logger from 'kolibri.lib.logging';
import importIntlLocale from './intl-locale-data';
import importVueIntlLocaleData from './vue-intl-locale-data';
import getPluginData from 'kolibri.utils.getPluginData';

export { licenseTranslations } from './licenseTranslations';

const logging = logger.getLogger(__filename);

const languageGlobals = getPluginData()['languageGlobals'] || {};

function $trWrapper(nameSpace, defaultMessages, formatter, messageId, args) {
  if (args) {
    if (!Array.isArray(args) && typeof args !== 'object') {
      logging.error(`The $tr functions take either an array of positional
                      arguments or an object of named options.`);
    }
  }
  const defaultMessageText = defaultMessages[messageId];
  const message = {
    id: `${nameSpace}.${messageId}`,
    defaultMessage: defaultMessageText,
  };

  return formatter(message, args);
}

export const languageDirections = {
  LTR: 'ltr',
  RTL: 'rtl',
};

const defaultLocale = 'en';

export const defaultLanguage = {
  id: 'en',
  lang_name: 'English',
  lang_direction: languageDirections.LTR,
};

export const languageValidator = language => {
  return ['id', 'lang_name', 'lang_direction'].reduce((valid, key) => valid && language[key], true);
};

export const availableLanguages = {
  en: defaultLanguage,
};

export let currentLanguage = defaultLocale;

// Default to ltr
export let languageDirection = languageDirections.LTR;

export const getContentLangDir = language => {
  return (language || {}).lang_direction || languageDirections.LTR;
};

export const getLangDir = id => {
  return (availableLanguages[id] || {}).lang_direction || languageDirections.LTR;
};

export const isRtl = id => {
  return getLangDir(id) === languageDirections.RTL;
};

export const languageDensities = {
  englishLike: 'english_like',
  tall: 'tall',
  dense: 'dense',
};

export let languageDensity = languageDensities.englishLike;

const languageDensityMapping = {
  ar: languageDensities.tall,
  bn: languageDensities.tall,
  fa: languageDensities.tall,
  gu: languageDensities.tall,
  hi: languageDensities.tall,
  ja: languageDensities.dense,
  km: languageDensities.tall,
  kn: languageDensities.tall,
  ko: languageDensities.dense,
  lo: languageDensities.tall,
  ml: languageDensities.tall,
  mr: languageDensities.tall,
  my: languageDensities.tall,
  ne: languageDensities.tall,
  pa: languageDensities.tall,
  si: languageDensities.tall,
  ta: languageDensities.tall,
  te: languageDensities.tall,
  th: languageDensities.tall,
  ur: languageDensities.tall,
  vi: languageDensities.tall,
  zh: languageDensities.dense,
};

function languageIdToCode(id) {
  return id.split('-')[0].toLowerCase();
}

function setLanguageDensity(id) {
  const langCode = languageIdToCode(id);
  // Set the exported languageDensity in JS
  languageDensity = languageDensityMapping[langCode] || languageDensities.englishLike;
  // Set the body class for global typography
  global.document.body.classList.add(`language-${languageDensity}`);
}

/**
 * Class exposing translation functions for a particular message name space.
 * @class
 */
class Translator {
  /**
   * Create a Translator object.
   * @param {string} nameSpace - The nameSpace of the messages for translation.
   * @param {object} defaultMessages - an object mapping message ids to default messages.
   */
  constructor(nameSpace, defaultMessages) {
    this.nameSpace = nameSpace;
    this.defaultMessages = defaultMessages;
  }
  $tr(messageId, args) {
    return $trWrapper(
      this.nameSpace,
      this.defaultMessages,
      vue.prototype.$formatMessage,
      messageId,
      args
    );
  }
  // For convenience, also proxy all vue intl translation methods on this object
  $formatDate(date, options = {}) {
    return vue.prototype.$formatDate(date, options);
  }
  $formatTime(time, options = {}) {
    return vue.prototype.$formatTime(time, options);
  }
  $formatRelative(date, options = {}) {
    return vue.prototype.$formatRelative(date, options);
  }
  $formatNumber(number, options = {}) {
    return vue.prototype.$formatNumber(number, options);
  }
  $formatPlural(plural, options = {}) {
    return vue.prototype.$formatPlural(plural, options);
  }
}

/**
 * Returns a Translator instance.
 * @param {string} nameSpace - The nameSpace of the messages for translation.
 * @param {object} defaultMessages - an object mapping message ids to default messages.
 */
export function createTranslator(nameSpace, defaultMessages) {
  return new Translator(nameSpace, defaultMessages);
}

/**
 * Returns a Translator instance that can grab strings from another component.
 * WARNINGS:
 *  - Cannot be used across plugin boundaries
 *  - Use sparingly, e.g. to bypass string freeze
 *  - Try to remove post-string-freeze
 * @param {Component} Component - An imported component.
 */
export function crossComponentTranslator(Component) {
  return new Translator(Component.name, Component.$trs);
}

function _setUpVueIntl() {
  /**
   * Use the vue-intl plugin.
   *
   * Note that this _must_ be called after i18nSetup because this function sets up
   * the currentLanguage module variable which is referenced inside of here.
   **/
  const VueIntl = require('vue-intl');
  vue.use(VueIntl, { defaultLocale });
  vue.prototype.isRtl = languageDirection === 'rtl';

  vue.prototype.$tr = function $tr(messageId, args) {
    const nameSpace = this.$options.name || this.$options.$trNameSpace;
    return $trWrapper(nameSpace, this.$options.$trs, this.$formatMessage, messageId, args);
  };

  vue.setLocale(currentLanguage);
  if (languageGlobals.coreLanguageMessages) {
    vue.registerMessages(currentLanguage, languageGlobals.coreLanguageMessages);
  }
  importVueIntlLocaleData().forEach(localeData => VueIntl.addLocaleData(localeData));
}

function _loadDefaultFonts() {
  /*
   * Eagerly load the full default fonts for the current language asynchronously, but
   * avoid referencing them until they've been fully loaded. This is done by adding a
   * class to the HTML root which has the effect of switching fonts from system defaults
   * to Noto.
   *
   * This prevents the text from being invisible while the fonts are loading ("FOIT")
   * and instead falls back on system fonts while they're loading ("FOUT").
   *
   * We need to do this even for 'modern' browsers, because not all browsers implement
   * fall-back behaviors of the font stacks correctly. See:
   *
   *    https://bugs.chromium.org/p/chromium/issues/detail?id=897539
   */

  // We use the <html> element to store the CSS 'loaded' class
  const htmlEl = document.documentElement;
  const FULL_FONTS = 'full-fonts-loaded';
  const PARTIAL_FONTS = 'partial-fonts-loaded';

  // Skip partial font usage and observer for Edge browser as a workaround for
  //   https://github.com/learningequality/kolibri/issues/4515
  // TODO: figure out exactly why this was happening and remove this logic.
  if (/Edge/.test(global.navigator.userAgent)) {
    htmlEl.classList.add(FULL_FONTS);
    return;
  }

  htmlEl.classList.add(PARTIAL_FONTS);

  const uiNormal = new FontFaceObserver('noto-full', { weight: 400 });
  const uiBold = new FontFaceObserver('noto-full', { weight: 700 });

  // passing the language name to 'load' for its glyphs, not its value per se
  const string = availableLanguages[currentLanguage].lang_name;
  Promise.all([uiNormal.load(string, 20000), uiBold.load(string, 20000)])
    .then(function() {
      htmlEl.classList.remove(PARTIAL_FONTS);
      htmlEl.classList.add(FULL_FONTS);
      logging.debug(`Loaded full font for '${currentLanguage}'`);
    })
    .catch(function() {
      logging.warn(`Could not load full font for '${currentLanguage}'`);
    });
}

export function i18nSetup(skipPolyfill = false) {
  /**
   * Load fonts, app strings, and Intl polyfills
   **/

  // Set up exported module variable
  if (languageGlobals.languageCode) {
    currentLanguage = languageGlobals.languageCode;
  }

  if (languageGlobals.languages) {
    Object.assign(availableLanguages, languageGlobals.languages);
  }

  languageDirection = languageGlobals.languageDir || languageDirection;

  // Set up typography
  setLanguageDensity(currentLanguage);
  _loadDefaultFonts();

  // If the browser doesn't support the Intl polyfill, we retrieve that and
  // the modules need to wait until that happens.
  return new Promise((resolve, reject) => {
    if (Object.prototype.hasOwnProperty.call(global, 'Intl') || skipPolyfill) {
      _setUpVueIntl();
      resolve();
    } else {
      Promise.all([
        new Promise(res => {
          require.ensure(
            ['intl'],
            require => {
              res(() => require('intl'));
            },
            'intl'
          );
        }),
        importIntlLocale(currentLanguage),
      ]).then(
        // eslint-disable-line
        ([requireIntl, requireIntlLocaleData]) => {
          requireIntl(); // requireIntl must run before requireIntlLocaleData
          requireIntlLocaleData();
          _setUpVueIntl();
          resolve();
        },
        error => {
          logging.error(error);
          logging.error('An error occurred trying to setup Internationalization', error);
          reject();
        }
      );
    }
  });
}

export function localeCompare(str1, str2) {
  // Catch if browser does not support extended localeCompare arguments
  try {
    // use 'search' option to ignore case rather than use locale defaults
    return String(str1).localeCompare(String(str2), 'default', { usage: 'search' });
  } catch (e) {
    return String(str1).localeCompare(String(str2));
  }
}
<|endoftext|>


<commit_before>import * as actionTypes from '../constants/ActionTypes';

import Immutable, { Map, List } from 'immutable';

import guid from '../lib/guid';

// TODO
// bifurcate reducers/actionTypes/actions on major feature

/* remove this when real data happens */
const initialDataSongsState = Immutable.fromJS({
	'id1': {
		inputs: {
			title: 'tracy\'s jacks',
			artist: 'blurry',
			album: 'parklifes',
			label: 'label 5',
			year: '1996',
			notes: 'it\'s a good song!',
		},
		played: false
	},
	'id2': {
		inputs: {
			title: 'Ride the Ligtening',
			artist: 'Metalica',
			album: 'Minister of Puppets',
			label: 'Label #420',
			year: '1987',
			notes: 'bang yr head',
		},
		played: true,
	},
	'id3': {
		inputs: {
			title: 'india was an angel',
			artist: 'guiding by voices',
			album: 'king ship && the golden boyz',
			label: 'scat records',
			year: '1993',
			notes: 'sweet spots 4 you',
		},
		played: true,
	}
});

const initialViewSongState = Immutable.fromJS({
	selected: 'id1'
});

const initialSongState = {
	inputs: {
		title: '',
		artist: '',
		album: '',
		label: '',
		year: '',
		notes: '',
	},
	played: false
};

export function state(state = Map({}), action) {
	return state
		.set('view', view(state.get('view'), action))
		.set('data', data(state.get('data'), action));
}

export function view(state = Map({}), action) {
	return state
		.set('set', viewSet(state.get('set'), action))
		.set('song', viewSong(state.get('song'), action));
}

export function viewSet(state = Map({}), action) {
  switch (action.type) {
  case actionTypes.SELECT_SET:
    return state.set('selected', action.id);
  default:
    return state;
  }
}

export function viewSong(state = initialViewSongState, action) {
  switch (action.type) {
  case actionTypes.SELECT_SONG:
    return state.set('selected', action.id);
	case actionTypes.SEARCH_FOR_SONG:
		debugger;
    return state;
  default:
    return state;
  }
}

export function data(state = Map({}), action) {
	return state
		.set('sets', dataSets(state.get('sets'), action))
		.set('songs', dataSongs(state.get('songs'), action));
}

export function dataSongs(state = initialDataSongsState, action) {
  switch (action.type) {
	case actionTypes.UPDATE_SONG:
		return state.setIn(
			[action.update.id, 'inputs', action.update.key],
			action.update.val
		);
	case actionTypes.ADD_SONG:
		// TODO: make this its own function
		let song = action.song;
		let newGuid = guid();
		let songObj = {};

		if (Object.keys(action.song).length == 0) {
			song = initialSongState;
		}

		songObj[newGuid] = Immutable.fromJS(song);

		return Immutable.Map(songObj).merge(state);
	case actionTypes.MARK_SONG_PLAYED:
		return state.setIn(
			[action.id, 'played'],
			!state.get(action.id).get('played')
		);
	case actionTypes.DELETE_SONG:
    return state.delete(action.id);
  default:
    return state;
  }
}

export function dataSets(state = Map({}), action) {
  switch (action.type) {
	case actionTypes.ADD_SET:
	case actionTypes.UPDATE_SET:
	case actionTypes.DELETE_SET:
		debugger;
    return state;
  default:
    return state;
  }
}
<commit_msg>Make initial state have no selected song<commit_after>import * as actionTypes from '../constants/ActionTypes';

import Immutable, { Map, List } from 'immutable';

import guid from '../lib/guid';

// TODO
// bifurcate reducers/actionTypes/actions on major feature

/* remove this when real data happens */
const initialDataSongsState = Immutable.fromJS({
	'id1': {
		inputs: {
			title: 'tracy\'s jacks',
			artist: 'blurry',
			album: 'parklifes',
			label: 'label 5',
			year: '1996',
			notes: 'it\'s a good song!',
		},
		played: false
	},
	'id2': {
		inputs: {
			title: 'Ride the Ligtening',
			artist: 'Metalica',
			album: 'Minister of Puppets',
			label: 'Label #420',
			year: '1987',
			notes: 'bang yr head',
		},
		played: true,
	},
	'id3': {
		inputs: {
			title: 'india was an angel',
			artist: 'guiding by voices',
			album: 'king ship && the golden boyz',
			label: 'scat records',
			year: '1993',
			notes: 'sweet spots 4 you',
		},
		played: true,
	}
});

const initialViewSongState = Immutable.fromJS({
	selected: ''
});

const initialSongState = {
	inputs: {
		title: '',
		artist: '',
		album: '',
		label: '',
		year: '',
		notes: '',
	},
	played: false
};

export function state(state = Map({}), action) {
	return state
		.set('view', view(state.get('view'), action))
		.set('data', data(state.get('data'), action));
}

export function view(state = Map({}), action) {
	return state
		.set('set', viewSet(state.get('set'), action))
		.set('song', viewSong(state.get('song'), action));
}

export function viewSet(state = Map({}), action) {
  switch (action.type) {
  case actionTypes.SELECT_SET:
    return state.set('selected', action.id);
  default:
    return state;
  }
}

export function viewSong(state = initialViewSongState, action) {
  switch (action.type) {
  case actionTypes.SELECT_SONG:
    return state.set('selected', action.id);
	case actionTypes.SEARCH_FOR_SONG:
		debugger;
    return state;
  default:
    return state;
  }
}

export function data(state = Map({}), action) {
	return state
		.set('sets', dataSets(state.get('sets'), action))
		.set('songs', dataSongs(state.get('songs'), action));
}

export function dataSongs(state = initialDataSongsState, action) {
  switch (action.type) {
	case actionTypes.UPDATE_SONG:
		return state.setIn(
			[action.update.id, 'inputs', action.update.key],
			action.update.val
		);
	case actionTypes.ADD_SONG:
		// TODO: make this its own function
		let song = action.song;
		let newGuid = guid();
		let songObj = {};

		if (Object.keys(action.song).length == 0) {
			song = initialSongState;
		}

		songObj[newGuid] = Immutable.fromJS(song);

		return Immutable.Map(songObj).merge(state);
	case actionTypes.MARK_SONG_PLAYED:
		return state.setIn(
			[action.id, 'played'],
			!state.get(action.id).get('played')
		);
	case actionTypes.DELETE_SONG:
    return state.delete(action.id);
  default:
    return state;
  }
}

export function dataSets(state = Map({}), action) {
  switch (action.type) {
	case actionTypes.ADD_SET:
	case actionTypes.UPDATE_SET:
	case actionTypes.DELETE_SET:
		debugger;
    return state;
  default:
    return state;
  }
}
<|endoftext|>


<commit_before>/* commonjs package manager support */
if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
    var autobahn = require('autobahn');
    var jsriffle = require('jsriffle');
    module.exports = 'vxWamp';
}

(function () {
    'use strict';

    jsriffle.setDevFabric();

    var vxWampModule = angular.module('vxWamp', []).provider('$wamp', $WampProvider);

    function $WampProvider() {
        var options;

        this.init = function (initOptions) {
            options = initOptions || {};
        };

        var interceptors = this.interceptors = [];

        this.$get = ["$rootScope", "$q", "$log", "$injector", function ($rootScope, $q, $log, $injector) {

            var connection;
            var sessionDeferred = $q.defer();
            var sessionPromise = sessionDeferred.promise;

            /**
             * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
             */
            var reversedInterceptors = [];

            angular.forEach(interceptors, function (interceptor) {
                reversedInterceptors.unshift(
                    angular.isString(interceptor) ? $injector.get(interceptor) :  $injector.invoke(interceptor));
            });

            /**
             * @param func
             * @returns {Function}
             *
             * @description
             * Wraps a callback with a function that calls scope.$apply(), so that the callback is added to the digest
             */
            function digestWrapper(func) {

                // if (options.disable_digest && options.disable_digest === true) {
                //     return func;
                // }

                return function () {
                    var cb = func.apply(this, arguments);
                    $rootScope.$apply();
                    return cb;
                };
            }

            // options = angular.extend({onchallenge: digestWrapper(onchallenge), use_deferred: $q.defer}, options);

            connection = new jsriffle.Domain(options);

            connection.onJoin = digestWrapper(function () {
                $rootScope.$broadcast("$wamp.open");
                sessionDeferred.resolve();
            });

            connection.onLeave = digestWrapper(function (reason, details) {
                $log.debug("Connection Closed: ", reason, details);
                sessionDeferred = $q.defer();
                sessionPromise = sessionDeferred.promise;
                $rootScope.$broadcast("$wamp.close", {reason: reason, details: details});
            });

            /**
             * Subscription object which self manages reconnections
             * @param topic
             * @param handler
             * @param options
             * @param subscribedCallback
             * @returns {{}}
             * @constructor
             */
            var Subscription = function (topic, handler, options, subscribedCallback) {

                var subscription = {}, unregister, onOpen, deferred = $q.defer();

                handler = digestWrapper(handler);

                onOpen = function () {
                    var p = connection.session.subscribe(topic, handler, options).then(
                        function (s) {
                            if (subscription.hasOwnProperty('id')) {
                                delete subscription.id;
                            }

                            subscription = angular.extend(s, subscription);
                            deferred.resolve(subscription);
                            return s;
                        }
                    );
                    if (subscribedCallback) {
                        subscribedCallback(p);
                    }

                };

                if (connection.isOpen) {
                    onOpen();
                }

                unregister = $rootScope.$on("$wamp.open", onOpen);

                subscription.promise = deferred.promise;
                subscription.unsubscribe = function () {
                    unregister(); //Remove the event listener, so this object can get cleaned up by gc
                    return connection.session.unsubscribe(subscription);
                };

                return subscription.promise;
            };

            /**
             * Wraps WAMP actions, so that when they're called, the defined interceptors get called before the result is returned
             *
             * @param type
             * @param args
             * @param callback
             * @returns {*}
             */
            var interceptorWrapper = function (type, args, callback) {

                var result = function (result) {
                    return {result: result, type: type, args: args};
                };

                var error = function (error) {
                    $log.error("$wamp error", {type: type, arguments: args, error: error});
                    return $q.reject({error: error, type: type, args: args});
                };

                // Only execute the action callback once we have an established session
                var action = sessionPromise.then(function () {
                    return callback();
                });

                var chain = [result, error];

                // Apply interceptors
                angular.forEach(reversedInterceptors, function (interceptor) {
                    if (interceptor[type + 'Response'] || interceptor[type + 'ResponseError']) {
                        chain.push(interceptor[type + 'Response'], interceptor[type + 'ResponseError']);
                    }
                });

                // We only want to return the actually result or error, not the entire information object
                chain.push(
                    function (response) {
                        return response.result;
                    }, function (response) {
                        return $q.reject(response.error);
                    }
                );

                while (chain.length) {
                    var resolved = chain.shift();
                    var rejected = chain.shift();

                    action = action.then(resolved, rejected);
                }

                return action;
            };

            return {
                connection: connection,
                open: function () {
                    connection.join();
                },
                // TODO
                leave: function () {
                    connection.leave();
                },
                // TODO
                // subscribe: function (topic, handler, options, subscribedCallback) {
                //     return interceptorWrapper('subscribe', arguments, function () {
                //         return Subscription(topic, handler, options, subscribedCallback);
                //     });
                // },
                // TODO
                subscribeOnScope: function (scope, channel, callback) {
                    return this.subscribe(channel, callback).then(function (subscription) {
                        scope.$on('$destroy', function () {
                            return subscription.unsubscribe();
                        });
                    });
                },
                // TODO
                unsubscribe: function (subscription) {
                    return interceptorWrapper('unsubscribe', arguments, function () {
                        return subscription.unsubscribe();
                    });
                },
                publish: function () {
                    var a = arguments

                    return interceptorWrapper('publish', arguments, function () {
                        return connection.publish.apply(connection, a);
                    });
                },
                register: function (action, handler) {
                    handler = digestWrapper(handler);

                    return interceptorWrapper('register', arguments, function () {
                        return connection.register(action, handler);
                    });
                },
                subscribe: function (action, handler) {
                    handler = digestWrapper(handler);

                    return interceptorWrapper('subscribe', arguments, function () {
                        return connection.subscribe(action, handler);
                    });
                },
                // TODO
                unregister: function (registration) {
                    return interceptorWrapper('unregister', arguments, function () {
                        return registration.unregister();
                    });
                },
                call: function (procedure, args, kwargs, options) {
                    var a = arguments

                    return interceptorWrapper('call', arguments, function () {
                        return connection.call.apply(connection, a);
                    });
                }
            };
        }];

        return this;

    }
})();<commit_msg>syntax complete<commit_after>/* commonjs package manager support */
if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
    var autobahn = require('autobahn');
    var jsriffle = require('jsriffle');
    module.exports = 'ngRiffle';
}

(function () {
    'use strict';

    jsriffle.setDevFabric();

    var ngRiffleModule = angular.module('ngRiffle', []).provider('$riffle', $RiffleProvider);

    function $RiffleProvider() {
        var options;

        this.init = function (initOptions) {
            options = initOptions || {};
        };

        var interceptors = this.interceptors = [];

        this.$get = ["$rootScope", "$q", "$log", "$injector", function ($rootScope, $q, $log, $injector) {

            var connection;
            var sessionDeferred = $q.defer();
            var sessionPromise = sessionDeferred.promise;

            /**
             * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
             */
            var reversedInterceptors = [];

            angular.forEach(interceptors, function (interceptor) {
                reversedInterceptors.unshift(
                    angular.isString(interceptor) ? $injector.get(interceptor) :  $injector.invoke(interceptor));
            });

            /**
             * @param func
             * @returns {Function}
             *
             * @description
             * Wraps a callback with a function that calls scope.$apply(), so that the callback is added to the digest
             */
            function digestWrapper(func) {

                // if (options.disable_digest && options.disable_digest === true) {
                //     return func;
                // }

                return function () {
                    var cb = func.apply(this, arguments);
                    $rootScope.$apply();
                    return cb;
                };
            }

            // options = angular.extend({onchallenge: digestWrapper(onchallenge), use_deferred: $q.defer}, options);

            connection = new jsriffle.Domain(options);

            connection.onJoin = digestWrapper(function () {
                $rootScope.$broadcast("$riffle.open");
                sessionDeferred.resolve();
            });

            connection.onLeave = digestWrapper(function (reason, details) {
                $log.debug("Connection Closed: ", reason, details);
                sessionDeferred = $q.defer();
                sessionPromise = sessionDeferred.promise;
                $rootScope.$broadcast("$riffle.close", {reason: reason, details: details});
            });

            /**
             * Subscription object which self manages reconnections
             * @param topic
             * @param handler
             * @param options
             * @param subscribedCallback
             * @returns {{}}
             * @constructor
             */
            var Subscription = function (topic, handler, options, subscribedCallback) {

                var subscription = {}, unregister, onOpen, deferred = $q.defer();

                handler = digestWrapper(handler);

                onOpen = function () {
                    var p = connection.session.subscribe(topic, handler, options).then(
                        function (s) {
                            if (subscription.hasOwnProperty('id')) {
                                delete subscription.id;
                            }

                            subscription = angular.extend(s, subscription);
                            deferred.resolve(subscription);
                            return s;
                        }
                    );
                    if (subscribedCallback) {
                        subscribedCallback(p);
                    }

                };

                if (connection.isOpen) {
                    onOpen();
                }

                unregister = $rootScope.$on("$riffle.open", onOpen);

                subscription.promise = deferred.promise;
                subscription.unsubscribe = function () {
                    unregister(); //Remove the event listener, so this object can get cleaned up by gc
                    return connection.session.unsubscribe(subscription);
                };

                return subscription.promise;
            };

            /**
             * Wraps WAMP actions, so that when they're called, the defined interceptors get called before the result is returned
             *
             * @param type
             * @param args
             * @param callback
             * @returns {*}
             */
            var interceptorWrapper = function (type, args, callback) {

                var result = function (result) {
                    return {result: result, type: type, args: args};
                };

                var error = function (error) {
                    $log.error("$riffle error", {type: type, arguments: args, error: error});
                    return $q.reject({error: error, type: type, args: args});
                };

                // Only execute the action callback once we have an established session
                var action = sessionPromise.then(function () {
                    return callback();
                });

                var chain = [result, error];

                // Apply interceptors
                angular.forEach(reversedInterceptors, function (interceptor) {
                    if (interceptor[type + 'Response'] || interceptor[type + 'ResponseError']) {
                        chain.push(interceptor[type + 'Response'], interceptor[type + 'ResponseError']);
                    }
                });

                // We only want to return the actually result or error, not the entire information object
                chain.push(
                    function (response) {
                        return response.result;
                    }, function (response) {
                        return $q.reject(response.error);
                    }
                );

                while (chain.length) {
                    var resolved = chain.shift();
                    var rejected = chain.shift();

                    action = action.then(resolved, rejected);
                }

                return action;
            };

            return {
                connection: connection,
                open: function () {
                    connection.join();
                },
                // TODO
                leave: function () {
                    connection.leave();
                },
                // TODO
                // subscribe: function (topic, handler, options, subscribedCallback) {
                //     return interceptorWrapper('subscribe', arguments, function () {
                //         return Subscription(topic, handler, options, subscribedCallback);
                //     });
                // },
                // TODO
                subscribeOnScope: function (scope, channel, callback) {
                    return this.subscribe(channel, callback).then(function (subscription) {
                        scope.$on('$destroy', function () {
                            return subscription.unsubscribe();
                        });
                    });
                },
                // TODO
                unsubscribe: function (subscription) {
                    return interceptorWrapper('unsubscribe', arguments, function () {
                        return subscription.unsubscribe();
                    });
                },
                publish: function () {
                    var a = arguments

                    return interceptorWrapper('publish', arguments, function () {
                        return connection.publish.apply(connection, a);
                    });
                },
                register: function (action, handler) {
                    handler = digestWrapper(handler);

                    return interceptorWrapper('register', arguments, function () {
                        return connection.register(action, handler);
                    });
                },
                subscribe: function (action, handler) {
                    handler = digestWrapper(handler);

                    return interceptorWrapper('subscribe', arguments, function () {
                        return connection.subscribe(action, handler);
                    });
                },
                // TODO
                unregister: function (registration) {
                    return interceptorWrapper('unregister', arguments, function () {
                        return registration.unregister();
                    });
                },
                call: function (procedure, args, kwargs, options) {
                    var a = arguments

                    return interceptorWrapper('call', arguments, function () {
                        return connection.call.apply(connection, a);
                    });
                }
            };
        }];

        return this;

    }
})();<|endoftext|>