<commit_before>// Copyright (c) 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * Route a request to an appropriate worker function, wait for it to return
 * a result, then asynchronously send it in a response.
 *
 * @private
 * @param {!Object<string, *>} request
 * @param {function(*): void} sendResponse
 * @return {void}
 */
var handleRequest_ = function(request, sendResponse) {
  var promise =
      request.type === 'call_api' ?
          callApi_(resolveApi_(request.api), request.args, request.options) :
      request.type === 'execute_script' ?
          executeScriptInTabs_(request.tabIds, request.code, request.options) :
      request.type === 'insert_css' ?
          insertCssIntoTabs_(request.tabIds, request.css, request.options) :
          Promise.reject('Unrecognized request type "' + request.type + '"');

  promise.then(function(result) {
    sendResponse({success: true, result: result});
  }).catch(function(error) {
    sendResponse({success: false, error: error.message ? error.message : error});
  });
};

/**
 * Resolve an API name to a corresponding API object, if any. This is generic,
 * i.e. not restricted to just the Chrome APIs.
 *
 * @private
 * @param {!string} apiName
 * @return {?Object} Resolved API object or null.
 */
var resolveApi_ = function(apiName) {
  var nameParts = apiName.split('.');
  var resolvedApi = window;
  for (var i = 0; i < nameParts.length; ++i) {
    resolvedApi = resolvedApi[nameParts[i]];
    if (!resolvedApi)
      return null;
  }
  return resolvedApi;
};

/**
 * A regexp for one particularly frequent error message that needs to be
 * translated for the client.
 *
 * @private @const
 */
var BAD_API_INVOCATION_ERROR_RE_ =
    /^Error: Invocation of form (.+) doesn't match definition (.+)$/;

/**
 * Invoke a Chrome API with the given name and arguments, and return the result
 * If the API's name resolves to something different from a function, and there
 * no arguments, the value of the resolved object is returned instead.
 *
 * @private
 * @param {Object} api
 * @param {!Object<string, *>} args
 * @param {{timeout: number}} options
 * @return {!Promise<*>} Result of the API call.
 */
var callApi_ = function(api, args, options) {
  return new Promise(function(resolve, reject) {
    if (!api) {
      return reject('No such API, or no permission to use it');
    }

    if (typeof api !== 'function') {
      // This can be an API property that the caller wants to read.
      if (args.length > 0) {
        return reject('This API is not a function: use with no arguments');
      }
      return resolve(api);
    }

    // Complete the promise either via a callback or a timeout.
    var timedOut = false;
    var timeout = null;
    if (options.timeout) {
      timeout = setTimeout(function() {
        timedOut = true;
        reject('Timed out');
      }, options.timeout);
    }

    var callback = function(result) {
      if (!timedOut) {
        clearTimeout(timeout);
        if (chrome.runtime.lastError) {
          reject(chrome.runtime.lastError);
        } else {
          resolve(result);
        }
      }
    };

    try {
      // `args` is an array, so we must use `apply` to invoke the API. The API,
      // however, requires a callback as one extra argument: append it to `args`.
      // NOTE: Since the callback of this call will resolve/reject the outer
      // Promise, make sure the following is the last call of this function.
      api.apply(null, args.concat([callback]));
    } catch (error) {
      if (!timedOut) {
        clearTimeout(timeout);
        var match = BAD_API_INVOCATION_ERROR_RE_.exec(error);
        if (match) {
          // Massage this particularly frequent error message to be clearer.
          reject(
              'Wrong API arguments: expected ' + match[2] +
              ' but got ' + match[1] + ' <= ' + JSON.stringify(args));
        } else {
          reject(error);
        }
      }
    }
  });
};

/**
 * Execute a script in the given tab's "isolated world" (with full access to
 * the DOM context but not the JavaScript context).
 *
 * The result of the executions is passed back as a single value for a single
 * requested tab, or as a map of form { tabId1: result1, ... } for multiple
 * requested tabs (special values 'all' and 'window' are considered multiple
 * tabs even if they resolve to just one).
 *
 * The execution is resilient to errors and/or timeouts in individual tabs,
 * which can happen for various reasons (the script itself never returns or
 * attempts to return too much data; a tab may be hung ("Aw, snap!"); a tab may
 * be a special chrome:// tab, in which scripts are prohibited and error out).
 * Such errors are returned in the results map as special string values.
 *
 * Request the Agent extension to execute the given script in the given list
 * of tabs, with the given options. The result of the executions is passed back
 * as a single value for a single requested tab, or as a map of form
 * { tabId1: result1, ... } for multiple requested tabs (special values 'all'
 * and 'window' are considered multiple tabs even if they resolve to just one).
 *
 * @private
 * @param {!number} tabId
 * @param {!string} code
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<*>}
 */
var executeScriptInTab_ = function(tabId, code, options) {
  // TODO(ussuri): Catch and return possible exceptions in the user's code.
  // The following didn't work:
  // code = 'try {' + code + '} catch (err) { console.log("CAUGHT"); err; }';
  var details = {
    code: code,
    allFrames: options.allFrames || false,
    runAt: options.runAt || 'document_idle'
  };

  return callApi_(chrome.tabs.executeScript, [tabId, details], options)
    .then(function(result) {
      return details.allFrames ? result: result[0];
    });
};

/**
 * Execute a script in the given tabs' "isolated world" (with full access to
 * the DOM context but not the JavaScript context).
 *
 * The result of the executions is passed back as a single value for a single
 * requested tab, or as a map of form { tabId1: result1, ... } for multiple
 * requested tabs (special values 'all' and 'window' are considered multiple
 * tabs even if they resolve to just one).
 *
 * The execution is resilient to errors and/or timeouts in individual tabs,
 * which can happen for various reasons (the script itself never returns or
 * attempts to return too much data; a tab may be hung ("Aw, snap!"); a tab may
 * be a special chrome:// tab, in which scripts are prohibited and error out).
 * Such errors are returned in the results map as special string values.
 *
 * Request the Agent extension to execute the given script in the given list
 * of tabs, with the given options. The result of the executions is passed back
 * as a single value for a single requested tab, or as a map of form
 * { tabId1: result1, ... } for multiple requested tabs (special values 'all'
 * and 'window' are considered multiple tabs even if they resolve to just one).
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @param {!string} code
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<Object<string, *>>}
 */
var executeScriptInTabs_ = function(tabIds, code, options) {
  return applyActionToTabs_(tabIds, executeScriptInTab_, [code, options]);
};

/**
 * Insert a fragment of CSS into the given tab and return the result of the
 * underlying API call (mostly useful in case of errors).
 *
 * @private
 * @param {!number} tabId
 * @param {!string} css
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<*>}
 */
var insertCssIntoTab_ = function(tabId, css, options) {
  var details = {
    code: css,
    allFrames: options.allFrames || false,
    runAt: options.runAt || 'document_idle'
  };
  return callApi_(chrome.tabs.insertCSS, [tabId, details], options);
};

/**
 * Insert the given CSS fragment into the given list of tabs, with the given
 * options. If there are any errors, they are returned as a single string for
 * a single requested tab, or as a map of form { tabId1: error1, ... } for
 * multiple requested tabs (special values 'all' and 'window' are considered
 * multiple tabs even if they resolve to just one).
 *
 * Note that the author styles take precedence over any iserted styles, so
 * if there is a clash for some setting, the inserted CSS will have no effect
 * (this is the limitation of the underlying Chrome API).
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @param {!string} css
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<Object<string, *>>}
 */
var insertCssIntoTabs_ = function(tabIds, css, options) {
  return applyActionToTabs_(tabIds, insertCssIntoTab_, [css, options]);
};

/**
 * Apply an action (a function-like entity) to the multiple requested tabs, and
 * return a map of form {tabId1: result1, ...}. Per-tab errors are reported as
 * strings with special values in the same map, but not flagged to the caller
 * in a more explicit way; that is, a call will always "succeed" from the
 * caller's perspective.
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @param {!function(!number, !string, {allFrames: boolean, runAt: string, timeout: number})} action
 * @param {!Array<*>} args
 * @return {!Promise<Object<string, *>>}
 */
var applyActionToTabs_ = function(tabIds, action, args) {
  // TODO(ussuri): Somehow return mixed results/errors, while explicitly
  // indicating to callers that error(s) have occurred.
  return normalizeTabIds_(tabIds).then(function(nTabIds) {
    var results = {};

    var applyAction = function(tabId) {
      return action.apply(null, [tabId].concat(args))
        .then(function(result) {
          results[tabId] = result;
        }).catch(function(error) {
          results[tabId] =
              '<ERROR: ' + (error.message ? error.message : error) + '>';
        });
    };

    var promises = nTabIds.map(function(tabId) {
      return applyAction(tabId);
    });
    return Promise.all(promises).then(function(_) {
      return results;
    });
  });
};

/**
 * Expand special values 'all' and 'window' of a tab ID list into an actual list
 * of IDs. Regular lists are returned as-is.
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @return {!Promise<!Array<number>>}
 */
var normalizeTabIds_ = function(tabIds) {
  if (!tabIds || tabIds === 'all') {
    return getAllTabIds_(false);
  } else if (tabIds === 'window') {
    return getAllTabIds_(true);
  } else {
    return /**@type {?}*/(Promise.resolve(tabIds));
  }
};

/**
 * Return a list of all tab IDs in all the open windows or the current
 * window only.
 *
 * @private
 * @param {boolean} thisWindowOnly
 * @return {!Promise<!Array<number>>} IDs of all the open tabs in all the windows.
 */
var getAllTabIds_ = function(thisWindowOnly) {
  return new Promise(function(resolve, reject) {
    // NOTE: {thisWindowOnly: false} means "other windows", but we want "all",
    // so use {}.
    var options = thisWindowOnly ? {currentWindow: true} : {};
    chrome.tabs.query(options, function(tabs) {
      resolve(tabs.map(function(tab) { return tab.id; }));
    });
  });
};

/**
 * This is the API end-point to listen to service requests from external clients.
 */
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    // TODO(ussuri): Verify the sender.
    handleRequest_(request, sendResponse);
    // Indicates that the response is sent asynchronously.
    return true;
  }
);

/**
 * @private @const
 */
var WEB_SHELL_TAB_PROPS_ = {
  title: 'Console',
  url: '*://*/**/web_shell/index.html'
};

/**
 * @private @const
 */
var HOSTED_WEB_SHELL_URL_ =
    'https://chromium.github.io/axiom/web_shell/index.html';

/**
 * @private @const
 */
var activeWebShellTabIdx_ = -1;

/**
 * Clicking on the extension icon in the toolbar will:
 * - If no tabs with the web shell are open, open a hosted shell in a new tab;
 * - If one or more tabs with the web shell are already open (e.g. a test
 *   and a hosted instances), then cycle through them.
 */
chrome.browserAction.onClicked.addListener(function() {
  chrome.tabs.query(WEB_SHELL_TAB_PROPS_, function(tabs) {
    if (tabs && tabs.length > 0) {
      ++activeWebShellTabIdx_;
      if (activeWebShellTabIdx_ >= tabs.length) {
        activeWebShellTabIdx_ = 0;
      }
      var tab = /** chrome.tabs.Tab */tabs[activeWebShellTabIdx_];
      chrome.tabs.update(tab.id, {active: true}, function() {});
      chrome.windows.update(tab.windowId, {focused: true}, function() {});
    } else {
      chrome.tabs.create({url: HOSTED_WEB_SHELL_URL_, active: true});
    }
  });
});
<commit_msg>Fix Closure error<commit_after>// Copyright (c) 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * Route a request to an appropriate worker function, wait for it to return
 * a result, then asynchronously send it in a response.
 *
 * @private
 * @param {!Object<string, *>} request
 * @param {function(*): void} sendResponse
 * @return {void}
 */
var handleRequest_ = function(request, sendResponse) {
  var promise =
      request.type === 'call_api' ?
          callApi_(resolveApi_(request.api), request.args, request.options) :
      request.type === 'execute_script' ?
          executeScriptInTabs_(request.tabIds, request.code, request.options) :
      request.type === 'insert_css' ?
          insertCssIntoTabs_(request.tabIds, request.css, request.options) :
          Promise.reject('Unrecognized request type "' + request.type + '"');

  promise.then(function(result) {
    sendResponse({success: true, result: result});
  }).catch(function(error) {
    sendResponse({success: false, error: error.message ? error.message : error});
  });
};

/**
 * Resolve an API name to a corresponding API object, if any. This is generic,
 * i.e. not restricted to just the Chrome APIs.
 *
 * @private
 * @param {!string} apiName
 * @return {?Object} Resolved API object or null.
 */
var resolveApi_ = function(apiName) {
  var nameParts = apiName.split('.');
  var resolvedApi = window;
  for (var i = 0; i < nameParts.length; ++i) {
    resolvedApi = resolvedApi[nameParts[i]];
    if (!resolvedApi)
      return null;
  }
  return resolvedApi;
};

/**
 * A regexp for one particularly frequent error message that needs to be
 * translated for the client.
 *
 * @private @const
 */
var BAD_API_INVOCATION_ERROR_RE_ =
    /^Error: Invocation of form (.+) doesn't match definition (.+)$/;

/**
 * Invoke a Chrome API with the given name and arguments, and return the result
 * If the API's name resolves to something different from a function, and there
 * no arguments, the value of the resolved object is returned instead.
 *
 * @private
 * @param {Object} api
 * @param {!Object<string, *>} args
 * @param {{timeout: number}} options
 * @return {!Promise<*>} Result of the API call.
 */
var callApi_ = function(api, args, options) {
  return new Promise(function(resolve, reject) {
    if (!api) {
      return reject('No such API, or no permission to use it');
    }

    if (typeof api !== 'function') {
      // This can be an API property that the caller wants to read.
      if (args.length > 0) {
        return reject('This API is not a function: use with no arguments');
      }
      return resolve(api);
    }

    // Complete the promise either via a callback or a timeout.
    var timedOut = false;
    var timeout = null;
    if (options.timeout) {
      timeout = setTimeout(function() {
        timedOut = true;
        reject('Timed out');
      }, options.timeout);
    }

    var callback = function(result) {
      if (!timedOut) {
        clearTimeout(timeout);
        if (chrome.runtime.lastError) {
          reject(chrome.runtime.lastError);
        } else {
          resolve(result);
        }
      }
    };

    try {
      // `args` is an array, so we must use `apply` to invoke the API. The API,
      // however, requires a callback as one extra argument: append it to `args`.
      // NOTE: Since the callback of this call will resolve/reject the outer
      // Promise, make sure the following is the last call of this function.
      api.apply(null, args.concat([callback]));
    } catch (error) {
      if (!timedOut) {
        clearTimeout(timeout);
        var match = BAD_API_INVOCATION_ERROR_RE_.exec(error);
        if (match) {
          // Massage this particularly frequent error message to be clearer.
          reject(
              'Wrong API arguments: expected ' + match[2] +
              ' but got ' + match[1] + ' <= ' + JSON.stringify(args));
        } else {
          reject(error);
        }
      }
    }
  });
};

/**
 * Execute a script in the given tab's "isolated world" (with full access to
 * the DOM context but not the JavaScript context).
 *
 * The result of the executions is passed back as a single value for a single
 * requested tab, or as a map of form { tabId1: result1, ... } for multiple
 * requested tabs (special values 'all' and 'window' are considered multiple
 * tabs even if they resolve to just one).
 *
 * The execution is resilient to errors and/or timeouts in individual tabs,
 * which can happen for various reasons (the script itself never returns or
 * attempts to return too much data; a tab may be hung ("Aw, snap!"); a tab may
 * be a special chrome:// tab, in which scripts are prohibited and error out).
 * Such errors are returned in the results map as special string values.
 *
 * Request the Agent extension to execute the given script in the given list
 * of tabs, with the given options. The result of the executions is passed back
 * as a single value for a single requested tab, or as a map of form
 * { tabId1: result1, ... } for multiple requested tabs (special values 'all'
 * and 'window' are considered multiple tabs even if they resolve to just one).
 *
 * @private
 * @param {!number} tabId
 * @param {!string} code
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<*>}
 */
var executeScriptInTab_ = function(tabId, code, options) {
  // TODO(ussuri): Catch and return possible exceptions in the user's code.
  // The following didn't work:
  // code = 'try {' + code + '} catch (err) { console.log("CAUGHT"); err; }';
  var details = {
    code: code,
    allFrames: options.allFrames || false,
    runAt: options.runAt || 'document_idle'
  };

  return callApi_(chrome.tabs.executeScript, [tabId, details], options)
    .then(function(result) {
      return details.allFrames ? result: result[0];
    });
};

/**
 * Execute a script in the given tabs' "isolated world" (with full access to
 * the DOM context but not the JavaScript context).
 *
 * The result of the executions is passed back as a single value for a single
 * requested tab, or as a map of form { tabId1: result1, ... } for multiple
 * requested tabs (special values 'all' and 'window' are considered multiple
 * tabs even if they resolve to just one).
 *
 * The execution is resilient to errors and/or timeouts in individual tabs,
 * which can happen for various reasons (the script itself never returns or
 * attempts to return too much data; a tab may be hung ("Aw, snap!"); a tab may
 * be a special chrome:// tab, in which scripts are prohibited and error out).
 * Such errors are returned in the results map as special string values.
 *
 * Request the Agent extension to execute the given script in the given list
 * of tabs, with the given options. The result of the executions is passed back
 * as a single value for a single requested tab, or as a map of form
 * { tabId1: result1, ... } for multiple requested tabs (special values 'all'
 * and 'window' are considered multiple tabs even if they resolve to just one).
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @param {!string} code
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<Object<string, *>>}
 */
var executeScriptInTabs_ = function(tabIds, code, options) {
  return applyActionToTabs_(tabIds, executeScriptInTab_, [code, options]);
};

/**
 * Insert a fragment of CSS into the given tab and return the result of the
 * underlying API call (mostly useful in case of errors).
 *
 * @private
 * @param {!number} tabId
 * @param {!string} css
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<*>}
 */
var insertCssIntoTab_ = function(tabId, css, options) {
  var details = {
    code: css,
    allFrames: options.allFrames || false,
    runAt: options.runAt || 'document_idle'
  };
  return callApi_(chrome.tabs.insertCSS, [tabId, details], options);
};

/**
 * Insert the given CSS fragment into the given list of tabs, with the given
 * options. If there are any errors, they are returned as a single string for
 * a single requested tab, or as a map of form { tabId1: error1, ... } for
 * multiple requested tabs (special values 'all' and 'window' are considered
 * multiple tabs even if they resolve to just one).
 *
 * Note that the author styles take precedence over any iserted styles, so
 * if there is a clash for some setting, the inserted CSS will have no effect
 * (this is the limitation of the underlying Chrome API).
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @param {!string} css
 * @param {{allFrames: boolean, runAt: string, timeout: number}} options
 * @return {!Promise<Object<string, *>>}
 */
var insertCssIntoTabs_ = function(tabIds, css, options) {
  return applyActionToTabs_(tabIds, insertCssIntoTab_, [css, options]);
};

/**
 * Apply an action (a function-like entity) to the multiple requested tabs, and
 * return a map of form {tabId1: result1, ...}. Per-tab errors are reported as
 * strings with special values in the same map, but not flagged to the caller
 * in a more explicit way; that is, a call will always "succeed" from the
 * caller's perspective.
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @param {!function(!number, !string, {allFrames: boolean, runAt: string, timeout: number})} action
 * @param {!Array<*>} args
 * @return {!Promise<Object<string, *>>}
 */
var applyActionToTabs_ = function(tabIds, action, args) {
  // TODO(ussuri): Somehow return mixed results/errors, while explicitly
  // indicating to callers that error(s) have occurred.
  return normalizeTabIds_(tabIds).then(function(nTabIds) {
    var results = {};

    var applyAction = function(tabId) {
      return action.apply(null, [tabId].concat(args))
        .then(function(result) {
          results[tabId] = result;
        }).catch(function(error) {
          results[tabId] =
              '<ERROR: ' + (error.message ? error.message : error) + '>';
        });
    };

    var promises = nTabIds.map(function(tabId) {
      return applyAction(tabId);
    });
    return Promise.all(promises).then(function(_) {
      return results;
    });
  });
};

/**
 * Expand special values 'all' and 'window' of a tab ID list into an actual list
 * of IDs. Regular lists are returned as-is.
 *
 * @private
 * @param {!(Array<number>|string)} tabIds
 * @return {!Promise<!Array<number>>}
 */
var normalizeTabIds_ = function(tabIds) {
  if (!tabIds || tabIds === 'all') {
    return getAllTabIds_(false);
  } else if (tabIds === 'window') {
    return getAllTabIds_(true);
  } else {
    return /**@type {?}*/(Promise.resolve(tabIds));
  }
};

/**
 * Return a list of all tab IDs in all the open windows or the current
 * window only.
 *
 * @private
 * @param {boolean} thisWindowOnly
 * @return {!Promise<!Array<number>>} IDs of all the open tabs in all the windows.
 */
var getAllTabIds_ = function(thisWindowOnly) {
  return new Promise(function(resolve, reject) {
    // NOTE: {thisWindowOnly: false} means "other windows", but we want "all",
    // so use {}.
    var options = thisWindowOnly ? {currentWindow: true} : {};
    chrome.tabs.query(options, function(tabs) {
      resolve(tabs.map(function(tab) { return tab.id; }));
    });
  });
};

/**
 * This is the API end-point to listen to service requests from external clients.
 */
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    // TODO(ussuri): Verify the sender.
    handleRequest_(request, sendResponse);
    // Indicates that the response is sent asynchronously.
    return true;
  }
);

/**
 * @private @const
 */
var WEB_SHELL_TAB_PROPS_ = {
  title: 'Console',
  url: '*://*/**/web_shell/index.html'
};

/**
 * @private @const
 */
var HOSTED_WEB_SHELL_URL_ =
    'https://chromium.github.io/axiom/web_shell/index.html';

/**
 * @private
 */
var activeWebShellTabIdx_ = -1;

/**
 * Clicking on the extension icon in the toolbar will:
 * - If no tabs with the web shell are open, open a hosted shell in a new tab;
 * - If one or more tabs with the web shell are already open (e.g. a test
 *   and a hosted instances), then cycle through them.
 */
chrome.browserAction.onClicked.addListener(function() {
  chrome.tabs.query(WEB_SHELL_TAB_PROPS_, function(tabs) {
    if (tabs && tabs.length > 0) {
      ++activeWebShellTabIdx_;
      if (activeWebShellTabIdx_ >= tabs.length) {
        activeWebShellTabIdx_ = 0;
      }
      var tab = /** chrome.tabs.Tab */tabs[activeWebShellTabIdx_];
      chrome.tabs.update(tab.id, {active: true}, function() {});
      chrome.windows.update(tab.windowId, {focused: true}, function() {});
    } else {
      chrome.tabs.create({url: HOSTED_WEB_SHELL_URL_, active: true});
    }
  });
});
<|endoftext|>


<commit_before>'use strict';
(function() {
    var Dom = Stimuli.core.Dom,
        Support = Stimuli.core.Support,
        Obj = Stimuli.core.Object;

    Stimuli.keyboard.specialKey.Enter = {

        getSequence: function(target) {
            var defaultEventConfig = {
                bubbles: true,
                cancelable: true,
                target: target
            },
            keyCode = 13,
            location = 0,
            sequence = [
                Obj.merge({
                    type: "keydown",
                    location: location,
                    keyCode: keyCode
                }, defaultEventConfig),
                Obj.merge({
                    type: "keypress",
                    location: location
                }, defaultEventConfig)
            ];

            if (Dom.isEditable(target)) {

                if (Dom.isInput(target)) {
                    var form = Dom.getAncestorForm(target);

                    if (form && Dom.hasSubmit(form)) {
                        sequence.push(function() {
                            form.submit();
                        });
                        return sequence;
                    }

                } else {

                    if (Support.isWebkit) {
                        sequence.push(Obj.merge({type: 'textInput', key: '\n'}, defaultEventConfig));
                    } else {
                        if (Dom.isTextArea(target)) {
                            sequence.push(function() {
                                Dom.updateEditableValue(target, '\n');
                            });
                        } else {
                            sequence.push(function() {
                                Dom.updateEditableHtml(target, '\n');
                            });
                        }

                        if (!Support.isIE8 && !Support.isIE9 && !Support.isIE10 && Dom.isTextArea(target)) {
                            sequence.push(Obj.merge({type: 'input'}, defaultEventConfig));
                        }
                    }
                }
            }

            sequence.push(Obj.merge({
                type: "keyup",
                location: location,
                keyCode: keyCode
            }, defaultEventConfig));

            return sequence;
        }
    };
})();<commit_msg>fix: IE11 was throwing a permission denied while navigating after a form.submit when typing enter  on a form input<commit_after>'use strict';
(function() {
    var Dom = Stimuli.core.Dom,
        Support = Stimuli.core.Support,
        Obj = Stimuli.core.Object;

    Stimuli.keyboard.specialKey.Enter = {

        getSequence: function(target) {
            var defaultEventConfig = {
                bubbles: true,
                cancelable: true,
                target: target
            },
            keyCode = 13,
            location = 0,
            sequence = [
                Obj.merge({
                    type: "keydown",
                    location: location,
                    keyCode: keyCode
                }, defaultEventConfig),
                Obj.merge({
                    type: "keypress",
                    location: location
                }, defaultEventConfig)
            ];

            if (Dom.isEditable(target)) {

                if (Dom.isInput(target)) {
                    var form = Dom.getAncestorForm(target);

                    if (form && Dom.hasSubmit(form)) {
                        sequence.push(function() {
                            if (Stimuli.core.Support.isIE11) {
                                Sizzle('body', document);
                            }
                            form.submit();
                        });
                        return sequence;
                    }

                } else {

                    if (Support.isWebkit) {
                        sequence.push(Obj.merge({type: 'textInput', key: '\n'}, defaultEventConfig));
                    } else {
                        if (Dom.isTextArea(target)) {
                            sequence.push(function() {
                                Dom.updateEditableValue(target, '\n');
                            });
                        } else {
                            sequence.push(function() {
                                Dom.updateEditableHtml(target, '\n');
                            });
                        }

                        if (!Support.isIE8 && !Support.isIE9 && !Support.isIE10 && Dom.isTextArea(target)) {
                            sequence.push(Obj.merge({type: 'input'}, defaultEventConfig));
                        }
                    }
                }
            }

            sequence.push(Obj.merge({
                type: "keyup",
                location: location,
                keyCode: keyCode
            }, defaultEventConfig));

            return sequence;
        }
    };
})();<|endoftext|>


<commit_before>module.exports = class Info {
  constructor (io, $mdToast, errorHandler) {
    this.email = this.email || '';
    this.io = io;
    this.$mdToast = $mdToast;
    this.errorHandler = errorHandler;
  }
  saveInfo () {
    console.log(this.email);
    // Do something to change email address (tbd)
  }
};
<commit_msg>Fix the build<commit_after>module.exports = class Info {
  constructor (io, $mdToast, errorHandler) {
    this.email = this.email || '';
    this.io = io;
    this.$mdToast = $mdToast;
    this.errorHandler = errorHandler;
  }
  saveInfo () {
    // Do something to change email address (tbd)
  }
};
<|endoftext|>


<commit_before>import crypto from 'crypto';
import { toSvg } from 'jdenticon';
import LS from 'lib/wallet/localStorage';
import details from 'lib/wallet/details';

export function getAvatar(size = 64) {
  const userInfo = details.get('userInfo');
  const email = (userInfo.email || '').trim().toLowerCase();
  let id;
  if (email) {
    const hash = crypto.createHash('md5').update(email).digest('hex');
    id = `gravatar:${hash}`;
  } else {
    const hash = crypto.createHmac('sha256', 'Coin Wallet').update(LS.getDetailsKey()).digest('hex');
    id = `identicon:${hash}`;
  }
  return {
    id,
    url: getAvatarUrl(id, size),
  };
}

export function getAvatarUrl(id, size) {
  const [type, hash] = id.split(':');
  if (type === 'gravatar') {
    return `https://www.gravatar.com/avatar/${hash}?size=${size}`;
  } else if (type === 'identicon') {
    return `data:image/svg+xml;base64,${Buffer.from(toSvg(hash, size, { padding: 0 })).toString('base64')}`;
  }
}

export default {
  getAvatar,
  getAvatarUrl,
};
<commit_msg>fix: getAvatar<commit_after>import crypto from 'crypto';
import { toSvg } from 'jdenticon';
import LS from 'lib/wallet/localStorage';
import details from 'lib/wallet/details';

export function getAvatar(size = 64) {
  const userInfo = details.get('userInfo');
  const email = (userInfo.email || '').trim().toLowerCase();
  let id;
  if (email) {
    const hash = crypto.createHash('md5').update(email).digest('hex');
    id = `gravatar:${hash}`;
  } else {
    const hash = crypto.createHmac('sha256', 'Coin Wallet').update(LS.getDetailsKey() || '').digest('hex');
    id = `identicon:${hash}`;
  }
  return {
    id,
    url: getAvatarUrl(id, size),
  };
}

export function getAvatarUrl(id, size) {
  const [type, hash] = id.split(':');
  if (type === 'gravatar') {
    return `https://www.gravatar.com/avatar/${hash}?size=${size}`;
  } else if (type === 'identicon') {
    return `data:image/svg+xml;base64,${Buffer.from(toSvg(hash, size, { padding: 0 })).toString('base64')}`;
  }
}

export default {
  getAvatar,
  getAvatarUrl,
};
<|endoftext|>


<commit_before>/**
 * Created by KGraham on 5/26/16.
 */
(function() {
    "use strict";

    angular.module("DCX")
        .constant("ENVIRONMENT_DEV", "development");

})();<commit_msg>Implementing better pattern for these constants<commit_after>/**
 * Created by KGraham on 5/26/16.
 */
(function() {
    "use strict";

    angular.module("DCX")
        .constant("ENVIRONMENT_TYPES", {
            DEV: "development",
            ITG: "integration",
            PRO: "production"
        });

})();<|endoftext|>


<commit_before>// Openlayers preview module

(function() {

    var $_ = _ // keep pointer to underscore, as '_' will may be overridden by a closure variable when down the stack

    this.ckan.module('olpreview', function (jQuery, _) {

        OpenLayers.Control.CKANLayerSwitcher = OpenLayers.Class(OpenLayers.Control.LayerSwitcher,
            {
                redraw: function () {
                    //if the state hasn't changed since last redraw, no need
                    // to do anything. Just return the existing div.
                    if (!this.checkRedraw()) {
                        return this.div;
                    }

                    //clear out previous layers
                    this.clearLayersArray("base");
                    this.clearLayersArray("data");

                    var containsOverlays = false;
                    var containsBaseLayers = false;

                    // Save state -- for checking layer if the map state changed.
                    // We save this before redrawing, because in the process of redrawing
                    // we will trigger more visibility changes, and we want to not redraw
                    // and enter an infinite loop.
                    this.layerStates = this.map.layers.map(function (layer) {
                        return {
                            'name': layer.name,
                            'visibility': layer.visibility,
                            'inRange': layer.inRange,
                            'id': layer.id
                        };
                    })

                    var layers = this.map.layers.slice().filter(function (layer) {
                        return layer.displayInLayerSwitcher
                    });
                    if (!this.ascending) {
                        layers.reverse();
                    }

                    for (var i = 0; i < layers.length; i++) {
                        var layer = layers[i];
                        var baseLayer = layer.isBaseLayer;

                        if (baseLayer) containsBaseLayers = true;
                        else containsOverlays = true;

                        // only check a baselayer if it is *the* baselayer, check data
                        //  layers if they are visible
                        var checked = (baseLayer) ? (layer == this.map.baseLayer) : layer.getVisibility();

                        // create input element
                        var inputElem = document.createElement("input"),
                        // The input shall have an id attribute so we can use
                        // labels to interact with them.
                            inputId = OpenLayers.Util.createUniqueID(this.id + "_input_");

                        inputElem.id = inputId;
                        inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name;
                        inputElem.type = (baseLayer) ? "radio" : "checkbox";
                        inputElem.value = layer.name;
                        inputElem.checked = checked;
                        inputElem.defaultChecked = checked;
                        inputElem.className = "olButton";
                        inputElem._layer = layer.id;
                        inputElem._layerSwitcher = this.id;
                        inputElem.disabled = !baseLayer && !layer.inRange;

                        // create span
                        var labelSpan = document.createElement("label");
                        // this isn't the DOM attribute 'for', but an arbitrary name we
                        // use to find the appropriate input element in <onButtonClick>
                        labelSpan["for"] = inputElem.id;
                        OpenLayers.Element.addClass(labelSpan, "labelSpan olButton");
                        labelSpan._layer = layer.id;
                        labelSpan._layerSwitcher = this.id;
                        if (!baseLayer && !layer.inRange) {
                            labelSpan.style.color = "gray";
                        }
                        labelSpan.innerHTML = layer.title || layer.name;
                        labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
                            : "baseline";

                        var groupArray = (baseLayer) ? this.baseLayers
                            : this.dataLayers;
                        groupArray.push({
                            'layer': layer,
                            'inputElem': inputElem,
                            'labelSpan': labelSpan
                        });

                        var groupDiv = $((baseLayer) ? this.baseLayersDiv
                            : this.dataLayersDiv);
                        groupDiv.append($("

").append($(inputElem)).append($(labelSpan)));
                    }

                    // if no overlays, dont display the overlay label
                    this.dataLbl.style.display = (containsOverlays) ? "" : "none";

                    // if no baselayers, dont display the baselayer label
                    this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";

                    return this.div;
                }
            }
        );

        var layerExtractors = {

            'kml': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createKMLLayer(url));
            },
            'gml': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createGMLLayer(url));
            },
            'geojson': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createGeoJSONLayer(url));
            },
            'wfs': function(resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var parsedUrl = resource.url.split('#');
                var url = proxyServiceUrl || parsedUrl[0];

                var ftName = parsedUrl.length > 1 && parsedUrl[1];
                OL_HELPERS.withFeatureTypesLayers(url, layerProcessor, ftName);
            },
            'wms' : function(resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var parsedUrl = resource.url.split('#');
                // use the original URL for the getMap, as there's no need for a proxy for image requests
                var getMapUrl = parsedUrl[0].split('?')[0]; // remove query if any

                var url = proxyServiceUrl || getMapUrl;

                var layerName = parsedUrl.length > 1 && parsedUrl[1];
                OL_HELPERS.withWMSLayers(url, getMapUrl, layerProcessor, layerName);
            },
            'esrigeojson': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createEsriGeoJSONLayer(url));
            },
            'arcgis_rest': function(resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var parsedUrl = resource.url.split('#');
                var url = proxyServiceUrl || parsedUrl[0];

                var layerName = parsedUrl.length > 1 && parsedUrl[1];

                OL_HELPERS.withArcGisLayers(parsedUrl[0], layerProcessor, layerName);
            },
            'gft': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var tableId = OL_HELPERS.parseURL(resource.url).query.docid;
                layerProcessor(OL_HELPERS.createGFTLayer(tableId, ckan.geoview.gapi_key));
            }
        }

        var withLayers = function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {

            var withLayers = layerExtractors[resource.format && resource.format.toLocaleLowerCase()];
            withLayers && withLayers(resource, proxyUrl, proxyServiceUrl, layerProcessor);
        }

        return {
            options: {
                i18n: {
                }
            },

            initialize: function () {
                jQuery.proxyAll(this, /_on/);
                this.el.ready(this._onReady);
            },

            addLayer: function (resourceLayer) {

                if (this.options.ol_config.hide_overlays &&
                    this.options.ol_config.hide_overlays.toLowerCase() == "true") {
                    resourceLayer.setVisibility(false);
                }

                this.map.addLayer(resourceLayer)

                var bbox = resourceLayer.getDataExtent && resourceLayer.getDataExtent()
                if (bbox) {
                    if (this.map.getExtent()) this.map.getExtent().extend(bbox)
                    else this.map.zoomToExtent(bbox)
                }
                else {
                    var firstExtent = false
                    resourceLayer.events.register(
                        "loadend",
                        resourceLayer,
                        function (e) {
                            if (!firstExtent) {
                                var bbox = e && e.object && e.object.getDataExtent && e.object.getDataExtent()
                                if (bbox)
                                    if (this.map.getExtent()) this.map.getExtent().extend(bbox)
                                    else this.map.zoomToExtent(bbox)
                                else
                                    this.map.zoomToMaxExtent()
                                firstExtent = true
                            }
                        })
                }

            },

            _commonBaseLayer: function(mapConfig) {
                /*
                Return an OpenLayers base layer to be used depending on CKAN wide settings

                TODO: factor out somewhere it can be reused by other modules.

                */

                var baseMapLayer;
                var urls;
                var attribution;

                var isHttps = window.location.href.substring(0, 5).toLowerCase() === 'https';
                if (mapConfig.type == 'mapbox') {
                    // MapBox base map
                    if (!mapConfig['mapbox.map_id'] || !mapConfig['mapbox.access_token']) {
                      throw '[CKAN Map Widgets] You need to provide a map ID ([account].[handle]) and an access token when using a MapBox layer. ' +
                            'See http://www.mapbox.com/developers/api-overview/ for details';
                    }

                    urls = ['//a.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                                '//b.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                                '//c.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                                '//d.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                    ];
                    attribution = '© Mapbox © OpenStreetMap  Improve this map';
                    baseMapLayer = new OpenLayers.Layer.XYZ('MapBox', urls, {
                        sphericalMercator: true,
                        wrapDateLine: true,
                        attribution: attribution
                    });
                } else if (mapConfig.type == 'custom') {
                    // Custom XYZ layer
                    urls = mapConfig['custom.url'];
                    if (urls.indexOf('${x}') === -1) {
                      urls = urls.replace('{x}', '${x}').replace('{y}', '${y}').replace('{z}', '${z}');
                    }
                    baseMapLayer = new OpenLayers.Layer.XYZ('Base Layer', urls, {
                        sphericalMercator: true,
                        wrapDateLine: true,
                        attribution: mapConfig.attribution
                    });
                } else {
                    // MapQuest OpenStreetMap base map
                    if (isHttps) {
                        var urls = ['//otile1-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile2-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile3-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile4-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png'];

                    } else {
                        var urls = ['//otile1.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile2.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile3.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile4.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png'];
                    }
                    var attribution = mapConfig.attribution || 'Map data © OpenStreetMap contributors, Tiles Courtesy of MapQuest ';

                    baseMapLayer = new OpenLayers.Layer.OSM('MapQuest OSM', urls, {
                      attribution: attribution});
                }

                return baseMapLayer;

            },

            _onReady: function () {

                // Choose base map based on CKAN wide config
                var baseMapLayer = this._commonBaseLayer(this.options.map_config);
                var clearBaseLayer = new OpenLayers.Layer.OSM("None", "/img/blank.gif", {isBaseLayer: true, attribution: ''});

                var mapDiv = $("

").attr("id", "map").addClass("map")
                var info = $("

").attr("id", "info")
                mapDiv.append(info)

                $("#data-preview").empty()
                $("#data-preview").append(mapDiv)

                info.tooltip({
                    animation: false,
                    trigger: 'manual',
                    placement: "right",
                    html: true
                });

                this.map = new OpenLayers.Map(
                    {
                        div: "map",
                        theme: "/js/vendor/openlayers2/theme/default/style.css",
                        layers: [baseMapLayer, clearBaseLayer],
                        maxExtent: baseMapLayer.getMaxExtent()
                        //projection: Mercator, // this is needed for WMS layers (most only accept 3857), but causes WFS to fail
                    });

                layerSwitcher = new OpenLayers.Control.CKANLayerSwitcher()

                this.map.addControl(layerSwitcher);

                var bboxFrag;
                var fragMap = OL_HELPERS.parseKVP((window.parent || window).location.hash && (window.parent || window).location.hash.substring(1));

                var bbox = (fragMap.bbox && new OpenLayers.Bounds(fragMap.bbox.split(',')).transform(EPSG4326, this.map.getProjectionObject()));
                if (bbox) this.map.zoomToExtent(bbox);

                var proxyUrl = this.options.proxy_url;
                var proxyServiceUrl = this.options.proxy_service_url;

                if (!ckan.geoview) ckan.geoview = {};
                ckan.geoview.googleApiKey = this.options.gapi_key;

                withLayers(preload_resource, proxyUrl, proxyServiceUrl, $_.bind(this.addLayer, this));

                // Expand layer switcher by default
                layerSwitcher.maximizeControl();

            }
        }
    });
})();
OpenLayers.ImgPath = '/js/vendor/openlayers2/img/';
<commit_msg>use proxy for arcgis_rest capabilities to work around wrong CORS headers from server<commit_after>// Openlayers preview module

(function() {

    var $_ = _ // keep pointer to underscore, as '_' will may be overridden by a closure variable when down the stack

    this.ckan.module('olpreview', function (jQuery, _) {

        OpenLayers.Control.CKANLayerSwitcher = OpenLayers.Class(OpenLayers.Control.LayerSwitcher,
            {
                redraw: function () {
                    //if the state hasn't changed since last redraw, no need
                    // to do anything. Just return the existing div.
                    if (!this.checkRedraw()) {
                        return this.div;
                    }

                    //clear out previous layers
                    this.clearLayersArray("base");
                    this.clearLayersArray("data");

                    var containsOverlays = false;
                    var containsBaseLayers = false;

                    // Save state -- for checking layer if the map state changed.
                    // We save this before redrawing, because in the process of redrawing
                    // we will trigger more visibility changes, and we want to not redraw
                    // and enter an infinite loop.
                    this.layerStates = this.map.layers.map(function (layer) {
                        return {
                            'name': layer.name,
                            'visibility': layer.visibility,
                            'inRange': layer.inRange,
                            'id': layer.id
                        };
                    })

                    var layers = this.map.layers.slice().filter(function (layer) {
                        return layer.displayInLayerSwitcher
                    });
                    if (!this.ascending) {
                        layers.reverse();
                    }

                    for (var i = 0; i < layers.length; i++) {
                        var layer = layers[i];
                        var baseLayer = layer.isBaseLayer;

                        if (baseLayer) containsBaseLayers = true;
                        else containsOverlays = true;

                        // only check a baselayer if it is *the* baselayer, check data
                        //  layers if they are visible
                        var checked = (baseLayer) ? (layer == this.map.baseLayer) : layer.getVisibility();

                        // create input element
                        var inputElem = document.createElement("input"),
                        // The input shall have an id attribute so we can use
                        // labels to interact with them.
                            inputId = OpenLayers.Util.createUniqueID(this.id + "_input_");

                        inputElem.id = inputId;
                        inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name;
                        inputElem.type = (baseLayer) ? "radio" : "checkbox";
                        inputElem.value = layer.name;
                        inputElem.checked = checked;
                        inputElem.defaultChecked = checked;
                        inputElem.className = "olButton";
                        inputElem._layer = layer.id;
                        inputElem._layerSwitcher = this.id;
                        inputElem.disabled = !baseLayer && !layer.inRange;

                        // create span
                        var labelSpan = document.createElement("label");
                        // this isn't the DOM attribute 'for', but an arbitrary name we
                        // use to find the appropriate input element in <onButtonClick>
                        labelSpan["for"] = inputElem.id;
                        OpenLayers.Element.addClass(labelSpan, "labelSpan olButton");
                        labelSpan._layer = layer.id;
                        labelSpan._layerSwitcher = this.id;
                        if (!baseLayer && !layer.inRange) {
                            labelSpan.style.color = "gray";
                        }
                        labelSpan.innerHTML = layer.title || layer.name;
                        labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
                            : "baseline";

                        var groupArray = (baseLayer) ? this.baseLayers
                            : this.dataLayers;
                        groupArray.push({
                            'layer': layer,
                            'inputElem': inputElem,
                            'labelSpan': labelSpan
                        });

                        var groupDiv = $((baseLayer) ? this.baseLayersDiv
                            : this.dataLayersDiv);
                        groupDiv.append($("

").append($(inputElem)).append($(labelSpan)));
                    }

                    // if no overlays, dont display the overlay label
                    this.dataLbl.style.display = (containsOverlays) ? "" : "none";

                    // if no baselayers, dont display the baselayer label
                    this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";

                    return this.div;
                }
            }
        );

        var layerExtractors = {

            'kml': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createKMLLayer(url));
            },
            'gml': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createGMLLayer(url));
            },
            'geojson': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createGeoJSONLayer(url));
            },
            'wfs': function(resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var parsedUrl = resource.url.split('#');
                var url = proxyServiceUrl || parsedUrl[0];

                var ftName = parsedUrl.length > 1 && parsedUrl[1];
                OL_HELPERS.withFeatureTypesLayers(url, layerProcessor, ftName);
            },
            'wms' : function(resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var parsedUrl = resource.url.split('#');
                // use the original URL for the getMap, as there's no need for a proxy for image requests
                var getMapUrl = parsedUrl[0].split('?')[0]; // remove query if any

                var url = proxyServiceUrl || getMapUrl;

                var layerName = parsedUrl.length > 1 && parsedUrl[1];
                OL_HELPERS.withWMSLayers(url, getMapUrl, layerProcessor, layerName);
            },
            'esrigeojson': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var url = proxyUrl || resource.url;
                layerProcessor(OL_HELPERS.createEsriGeoJSONLayer(url));
            },
            'arcgis_rest': function(resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var parsedUrl = resource.url.split('#');
                var url = proxyServiceUrl || parsedUrl[0];

                var layerName = parsedUrl.length > 1 && parsedUrl[1];

                OL_HELPERS.withArcGisLayers(url, layerProcessor, layerName, parsedUrl[0]);
            },
            'gft': function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {
                var tableId = OL_HELPERS.parseURL(resource.url).query.docid;
                layerProcessor(OL_HELPERS.createGFTLayer(tableId, ckan.geoview.gapi_key));
            }
        }

        var withLayers = function (resource, proxyUrl, proxyServiceUrl, layerProcessor) {

            var withLayers = layerExtractors[resource.format && resource.format.toLocaleLowerCase()];
            withLayers && withLayers(resource, proxyUrl, proxyServiceUrl, layerProcessor);
        }

        return {
            options: {
                i18n: {
                }
            },

            initialize: function () {
                jQuery.proxyAll(this, /_on/);
                this.el.ready(this._onReady);
            },

            addLayer: function (resourceLayer) {

                if (this.options.ol_config.hide_overlays &&
                    this.options.ol_config.hide_overlays.toLowerCase() == "true") {
                    resourceLayer.setVisibility(false);
                }

                this.map.addLayer(resourceLayer)

                var bbox = resourceLayer.getDataExtent && resourceLayer.getDataExtent()
                if (bbox) {
                    if (this.map.getExtent()) this.map.getExtent().extend(bbox)
                    else this.map.zoomToExtent(bbox)
                }
                else {
                    var firstExtent = false
                    resourceLayer.events.register(
                        "loadend",
                        resourceLayer,
                        function (e) {
                            if (!firstExtent) {
                                var bbox = e && e.object && e.object.getDataExtent && e.object.getDataExtent()
                                if (bbox)
                                    if (this.map.getExtent()) this.map.getExtent().extend(bbox)
                                    else this.map.zoomToExtent(bbox)
                                else
                                    this.map.zoomToMaxExtent()
                                firstExtent = true
                            }
                        })
                }

            },

            _commonBaseLayer: function(mapConfig) {
                /*
                Return an OpenLayers base layer to be used depending on CKAN wide settings

                TODO: factor out somewhere it can be reused by other modules.

                */

                var baseMapLayer;
                var urls;
                var attribution;

                var isHttps = window.location.href.substring(0, 5).toLowerCase() === 'https';
                if (mapConfig.type == 'mapbox') {
                    // MapBox base map
                    if (!mapConfig['mapbox.map_id'] || !mapConfig['mapbox.access_token']) {
                      throw '[CKAN Map Widgets] You need to provide a map ID ([account].[handle]) and an access token when using a MapBox layer. ' +
                            'See http://www.mapbox.com/developers/api-overview/ for details';
                    }

                    urls = ['//a.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                                '//b.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                                '//c.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                                '//d.tiles.mapbox.com/v4/' + mapConfig['mapbox.map_id'] + '/${z}/${x}/${y}.png?access_token=' + mapConfig['mapbox.access_token'],
                    ];
                    attribution = '© Mapbox © OpenStreetMap  Improve this map';
                    baseMapLayer = new OpenLayers.Layer.XYZ('MapBox', urls, {
                        sphericalMercator: true,
                        wrapDateLine: true,
                        attribution: attribution
                    });
                } else if (mapConfig.type == 'custom') {
                    // Custom XYZ layer
                    urls = mapConfig['custom.url'];
                    if (urls.indexOf('${x}') === -1) {
                      urls = urls.replace('{x}', '${x}').replace('{y}', '${y}').replace('{z}', '${z}');
                    }
                    baseMapLayer = new OpenLayers.Layer.XYZ('Base Layer', urls, {
                        sphericalMercator: true,
                        wrapDateLine: true,
                        attribution: mapConfig.attribution
                    });
                } else {
                    // MapQuest OpenStreetMap base map
                    if (isHttps) {
                        var urls = ['//otile1-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile2-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile3-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile4-s.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png'];

                    } else {
                        var urls = ['//otile1.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile2.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile3.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png',
                                    '//otile4.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png'];
                    }
                    var attribution = mapConfig.attribution || 'Map data © OpenStreetMap contributors, Tiles Courtesy of MapQuest ';

                    baseMapLayer = new OpenLayers.Layer.OSM('MapQuest OSM', urls, {
                      attribution: attribution});
                }

                return baseMapLayer;

            },

            _onReady: function () {

                // Choose base map based on CKAN wide config
                var baseMapLayer = this._commonBaseLayer(this.options.map_config);
                var clearBaseLayer = new OpenLayers.Layer.OSM("None", "/img/blank.gif", {isBaseLayer: true, attribution: ''});

                var mapDiv = $("

").attr("id", "map").addClass("map")
                var info = $("

").attr("id", "info")
                mapDiv.append(info)

                $("#data-preview").empty()
                $("#data-preview").append(mapDiv)

                info.tooltip({
                    animation: false,
                    trigger: 'manual',
                    placement: "right",
                    html: true
                });

                this.map = new OpenLayers.Map(
                    {
                        div: "map",
                        theme: "/js/vendor/openlayers2/theme/default/style.css",
                        layers: [baseMapLayer, clearBaseLayer],
                        maxExtent: baseMapLayer.getMaxExtent()
                        //projection: Mercator, // this is needed for WMS layers (most only accept 3857), but causes WFS to fail
                    });

                layerSwitcher = new OpenLayers.Control.CKANLayerSwitcher()

                this.map.addControl(layerSwitcher);

                var bboxFrag;
                var fragMap = OL_HELPERS.parseKVP((window.parent || window).location.hash && (window.parent || window).location.hash.substring(1));

                var bbox = (fragMap.bbox && new OpenLayers.Bounds(fragMap.bbox.split(',')).transform(EPSG4326, this.map.getProjectionObject()));
                if (bbox) this.map.zoomToExtent(bbox);

                var proxyUrl = this.options.proxy_url;
                var proxyServiceUrl = this.options.proxy_service_url;

                if (!ckan.geoview) ckan.geoview = {};
                ckan.geoview.googleApiKey = this.options.gapi_key;

                withLayers(preload_resource, proxyUrl, proxyServiceUrl, $_.bind(this.addLayer, this));

                // Expand layer switcher by default
                layerSwitcher.maximizeControl();

            }
        }
    });
})();
OpenLayers.ImgPath = '/js/vendor/openlayers2/img/';
<|endoftext|>


<commit_before>const Promise = require('bluebird');
const fsExtra = Promise.promisifyAll(require('fs-extra'));
const fs   = Promise.promisifyAll(require('fs'));
const uuid = require('uuid');
const exec = require('child_process').exec;

class Disassembler {

  constructor(options={logger, guid}) {
    this.logger = options.logger;
    this.guid = options.guid;
  }

  run(code, done, tmpDir="/tmp/javabytes") {
    this.findUniqueDir(tmpDir)
    .then((args) => {
      return this.makeDir({dirName: args.dirName, code});
    })
    .then((args) => {
      return this.compileJavaFile(args);
    })
    .then((args) => {
      return this.disassemble(args);
    })
    .then((args) => {
      return this.cleanup(args);
    })
    .then((obj) => {
      done(obj);
    })
    .catch((obj) => {
      done(obj);
    });
  }

  // make a tmp dir where work can happen
  makeDir(obj) {
    const dirName = obj.dirName;
    const code = obj.code;
    return new Promise((resolve, reject) => {
      fsExtra.mkdirs(dirName, function(err) {
        if (err) {
          reject(err);
        } else {
          resolve({dirName, code});
        }
      });
    });
  }

  // creates and compiles the java source
  compileJavaFile(obj) {
    const dirName = obj.dirName;
    const code = obj.code;
    return new Promise((resolve, reject) => {
      const classname = this.extractClass(code);
      const fileLocation = `${dirName}/${classname}.java`;

      fsExtra.outputFile(fileLocation, code, (err) => {
        if (err) {
          this.logger.error(err);
          reject({
            errors: "Unable to create file"
          });
        }

        const cmd = `javac ${fileLocation}`;
        exec(cmd, (error, stdout, stderr) => {
          if (stderr) {
            this.logger.error(stderr);
            reject({
              errors: this.cleanseOutput(stderr, `${dirName}/`)
            });
          } else {
            resolve({dirName, classname});
          }
        });
      });
    });
  }

  // disassembles the given source class file
  disassemble(obj) {
    const dirName = obj.dirName;
    const classname = obj.classname;
    return new Promise( (resolve, reject) => {
      const cmd = `javap -c ${dirName}/${classname}.class`;
      exec(cmd, (error, stdout, stderr) => {
        if (stderr) {
          this.logger.error(stderr);
          reject({
            errors: this.cleanseOutput(stderr, `${dirName}/`)
          });
        } else {
          resolve({
            result: stdout,
            dirName
          });
        }
      });
    });
  }

  // delete tmp files
  cleanup(obj) {
    const dirName = obj.dirName;
    const result = obj.result;
    return new Promise((resolve, reject) => {
      fsExtra.remove(dirName, function(){});
      resolve({result});
    });
  }

  // find a unique directory name
  findUniqueDir(tmpDir) {
    const guid = uuid.v4().replace(/-/g, '');
    const dirName = `${tmpDir}/${guid}`;
    return new Promise((resolve, reject) => {
      fs.stat(dirName, (err, stats) => {
        if (err) {
          resolve({dirName});
        } else {
          findUniqueDir();
        }
      });
    });
  }

  // extract class name
  extractClass(code) {
    const pattern = /\s*(public|private)\s+class\s+(\w+)\s+((extends\s+\w+)|(implements\s+\w+( ,\w+)*))?\s*\{/;
    const matches = pattern.exec(code);
    if (matches) {
      return matches[2];
    } else {
      return uuid.v4();
    }
  }

  // remove the randomly generated dir names and make it into a valid json obj
  cleanseOutput(output, location) {
    const re = new RegExp(location, "g");
    return output.replace(re, '').replace(/"/g, '\\"');
  }
}

module.exports = Disassembler;
<commit_msg>cleaned up dissassembler error handling<commit_after>const Promise = require('bluebird');
const fsExtra = Promise.promisifyAll(require('fs-extra'));
const fs   = Promise.promisifyAll(require('fs'));
const uuid = require('uuid');
const exec = require('child_process').exec;

class Disassembler {

  constructor(options={logger, guid}) {
    this.logger = options.logger;
    this.guid = options.guid;
  }

  run(code, done, tmpDir="/tmp/javabytes") {
    this.findUniqueDir(tmpDir)
    .then((args) => {
      return this.makeDir({dirName: args.dirName, code});
    })
    .then((args) => {
      return this.compileJavaFile(args);
    })
    .then((args) => {
      return this.disassemble(args);
    })
    .then((args) => {
      return this.cleanup(args);
    })
    .then((obj) => {
      done(obj);
    })
    .catch((obj) => {
      done(obj);
    });
  }

  // make a tmp dir where work can happen
  makeDir(obj) {
    const dirName = obj.dirName;
    const code = obj.code;
    return new Promise((resolve, reject) => {
      fsExtra.mkdirs(dirName, function(err) {
        if (err) {
          reject(err);
        } else {
          resolve({dirName, code});
        }
      });
    });
  }

  // creates and compiles the java source
  compileJavaFile(obj) {
    const dirName = obj.dirName;
    const code = obj.code;
    return new Promise((resolve, reject) => {
      const classname = this.extractClass(code);
      const fileLocation = `${dirName}/${classname}.java`;

      fsExtra.outputFile(fileLocation, code, (err) => {
        if (err) {
          this.logger.error(err);
          reject({
            errors: "Unable to create file"
          });
        }

        exec(`javac ${fileLocation}`, {shell: '/bin/bash'}, (error, stdout, stderr) => {
          if (error) {
            this.logger.error(`${this.guid}: Error -> ${error}`);
            reject({ errors: error });
          } else if (stderr) {
            this.logger.error(`${this.guid}: Stderr-> ${stderr}`);
            reject({ errors: this.cleanseOutput(stderr, `${dirName}/`) });
          } else {
            this.logger.verbose(`${this.guid}: Disassembling successful`);
            resolve({dirName, classname});
          }
        });
      });
    });
  }

  // disassembles the given source class file
  disassemble(obj) {
    const dirName = obj.dirName;
    const classname = obj.classname;
    return new Promise( (resolve, reject) => {
      const cmd = `javap -c ${dirName}/${classname}.class`;
      exec(cmd, (error, stdout, stderr) => {
        if (stderr) {
          this.logger.error(stderr);
          reject({
            errors: this.cleanseOutput(stderr, `${dirName}/`)
          });
        } else {
          resolve({
            result: stdout,
            dirName
          });
        }
      });
    });
  }

  // delete tmp files
  cleanup(obj) {
    const dirName = obj.dirName;
    const result = obj.result;
    return new Promise((resolve, reject) => {
      fsExtra.remove(dirName, function(){});
      resolve({result});
    });
  }

  // find a unique directory name
  findUniqueDir(tmpDir) {
    const guid = uuid.v4().replace(/-/g, '');
    const dirName = `${tmpDir}/${guid}`;
    return new Promise((resolve, reject) => {
      fs.stat(dirName, (err, stats) => {
        if (err) {
          resolve({dirName});
        } else {
          findUniqueDir();
        }
      });
    });
  }

  // extract class name
  extractClass(code) {
    const pattern = /\s*(public|private)\s+class\s+(\w+)\s+((extends\s+\w+)|(implements\s+\w+( ,\w+)*))?\s*\{/;
    const matches = pattern.exec(code);
    if (matches) {
      return matches[2];
    } else {
      return uuid.v4();
    }
  }

  // remove the randomly generated dir names and make it into a valid json obj
  cleanseOutput(output, location) {
    const re = new RegExp(location, "g");
    return output.replace(re, '').replace(/"/g, '\\"');
  }
}

module.exports = Disassembler;
<|endoftext|>


<commit_before>angular.module('jam.groups', [])

.controller('GroupsController', ['$scope', 'Auth', 'Groups', function($scope, Auth, Groups) {
  $scope.user = {};
  $scope.newGroup = {};
  $scope.data = {};
  $scope.modalShown = false;

  $scope.filterGroups = function (group) {
    return function(group) {
      return group.id !== $scope.user.currentGroupId;
    }
  };

  $scope.toggleModal = function () {
    $scope.modalShown = !$scope.modalShown;
  };

  $scope.createGroup = function () {
    Groups.createGroup($scope.newGroup)
    .then(function (group) {
      Groups.addUser(group.id, $scope.user.id)
      .then(function () {
        $scope.modalShown = false;
        $scope.user.currentGroupId = group.id;
        $scope.user.currentGroup = group;
        $scope.updateProfile($scope.user)
      });
    });
  };

  $scope.setCurrentGroup = function(group) {
    Auth.updateProfile({currentGroup: group, currentGroupId: group.id})
    .then(function (res) {
      $scope.user = res.data.user;
      window.location.reload();
    })
    .catch(function (error) {
      console.error(error);
    });
  };

  $scope.updateProfile = function () {
    return Auth.updateProfile($scope.user)
    .then(function (res) {
      $scope.user = res.data.user;
    })
    .catch(function (error) {
      console.error(error);
    });
  };

  // Load groups and group users
  Auth.getUserData()
  .then(function (userData) {
    $scope.user = userData;
    Groups.getGroupsByUserId(userData.id)
    .then(function (groups) {
      $scope.data.groups = groups;
    });
    Groups.getUsersByGroupId(userData.currentGroupId)
    .then(function (users) {
      $scope.data.users = users;
    });
  })
  .catch(console.error);
}]);<commit_msg>(cleanup) Remove unnecessary input to set current group function<commit_after>angular.module('jam.groups', [])

.controller('GroupsController', ['$scope', 'Auth', 'Groups', function($scope, Auth, Groups) {
  $scope.user = {};
  $scope.newGroup = {};
  $scope.data = {};
  $scope.modalShown = false;

  $scope.filterGroups = function (group) {
    return function(group) {
      return group.id !== $scope.user.currentGroupId;
    }
  };

  $scope.toggleModal = function () {
    $scope.modalShown = !$scope.modalShown;
  };

  $scope.createGroup = function () {
    Groups.createGroup($scope.newGroup)
    .then(function (group) {
      Groups.addUser(group.id, $scope.user.id)
      .then(function () {
        $scope.modalShown = false;
        $scope.user.currentGroupId = group.id;
        $scope.user.currentGroup = group;
        $scope.updateProfile($scope.user)
      });
    });
  };

  $scope.setCurrentGroup = function(group) {
    Auth.updateProfile({currentGroupId: group.id})
    .then(function (res) {
      $scope.user = res.data.user;
      window.location.reload();
    })
    .catch(function (error) {
      console.error(error);
    });
  };

  $scope.updateProfile = function () {
    return Auth.updateProfile($scope.user)
    .then(function (res) {
      $scope.user = res.data.user;
    })
    .catch(function (error) {
      console.error(error);
    });
  };

  // Load groups and group users
  Auth.getUserData()
  .then(function (userData) {
    $scope.user = userData;
    Groups.getGroupsByUserId(userData.id)
    .then(function (groups) {
      $scope.data.groups = groups;
    });
    Groups.getUsersByGroupId(userData.currentGroupId)
    .then(function (users) {
      $scope.data.users = users;
    });
  })
  .catch(console.error);
}]);<|endoftext|>


<commit_before>var Human = (function() {
    function Human(game_state, x, y) {
        MovingSprite.call(this, game_state, x, y, 'human', 'humans');
        this.speed = 100;
        this.body.allowGravity = false;
		this.game = game_state.game;

        this.game.physics.arcade.enable(this);

        this.framesPerSecond = 10;

        this.moves = ['moveUp', 'moveDown', 'moveLeft', 'moveRight'];

		this.lastMove = null;

        this.devourHuman = function(human, enemy) {
            this.game_state.world_state.devourHuman(human);

            this.makeNastyScreams();
            this.makeNastyEatingNoises();
            this.makeNastyMess(human);

            human.kill();
        };

        this.humanHitsSummon = function(human, summon) {
            if (!summon.fallTween.isRunning && human.alive) {
                var cloneH = this.game_state.game.add.sprite(summon.x, summon.y, 'summon');
                cloneH.anchor.set(0.5);

                var cloneV = this.game_state.game.add.sprite(summon.x, summon.y, 'summon');
                cloneV.anchor.set(0.5);

                this.makeNastyScreams();

                var explosionSpeed = 250;

                this.game_state.game.add.tween(cloneV.scale).to({
                    x: 0.10,
                    y: 10
                }, explosionSpeed, "Expo.easeOut", true, 0);
                this.game_state.game.add.tween(cloneH.scale).to({
                    x: 10,
                    y: 0.10
                }, explosionSpeed, "Expo.easeOut", true, 0);
                this.game.add.tween(cloneH).to({
                    alpha: 0
                }, 250, "Linear", true, 250);
                this.game.add.tween(cloneV).to({
                    alpha: 0
                }, 250, "Linear", true, 250);

                this.game_state.character.addFollower(new Ghost(this.game_state, human.x, human.y));
                this.game_state.world_state.sacrificeHuman(this);

                human.kill();
                summon.kill();
            }
        };

		this.terrainHit = function(human){
			human.forceDirectionChange = true;
		};

        this.animations.add('down', [0, 1, 2, 3, 4, 5], this.framesPerSecond, true);
        this.animations.add('right', [18, 19, 20, 21, 22, 23], this.framesPerSecond, true);
        this.animations.add('up', [12, 13, 14, 15, 16, 17], this.framesPerSecond, true);
        this.animations.add('left', [6, 7, 8, 9, 10, 11], this.framesPerSecond, true);

    };

    Human.prototype = Object.create(MovingSprite.prototype);
    Human.prototype.constructor = Human;

    Human.prototype.update = function() {
         "use strict";
		this.game.physics.arcade.collide(this.game_state.humans, this.game_state.backgroundLayer, this.terrainHit);
		if (this.alive) {
			this.game_state.game.physics.arcade.overlap(this, this.game_state.summonLayer, this.humanHitsSummon, null, this);
			this.game_state.game.physics.arcade.overlap(this, this.game_state.enemy, this.devourHuman, null, this);
			var moveIn = this.lastMove;

			if (this.forceDirectionChange || !this.lastMove || Math.random() > 0.98) {
				this.forceDirectionChange = false;
				moveIn = this.moves[Math.floor(Math.random() * 10) % 4];
			}
			this[moveIn]();
			this.lastMove = moveIn;
			if (this.y > this.game_state.game.height || this.y < 0 || this.x > this.game_state.game.height || this.x < 0) this.destroy();

			this.game_state.emitter.emitX = this.game_state.enemy.x;
	        this.game_state.emitter.emitY = this.game_state.enemy.y;
		}
    };

    Human.prototype.makeNastyScreams = function() {
        this.game_state.screams[this.game.rnd.between(0, this.game_state.screams.length - 1)].play();
    };

    Human.prototype.makeNastyEatingNoises = function() {
        this.game_state.eating[this.game.rnd.between(0, this.game_state.eating.length - 1)].play();
    };

    Human.prototype.makeNastyMess = function(human) {
        var bodyPartOneFrame = Math.floor(Math.random() * 2);
        var bodyPartTwoFrame = Math.floor(Math.random() * 2) + 2;

        var bodyPartOneX = Math.floor(Math.random() * 5);
        var bodyPartOneY = Math.floor(Math.random() * 5);

        var bodyPartTwoX = Math.floor(Math.random() * 5);
        var bodyPartTwoY = Math.floor(Math.random() * 5);

        var bodyPartOne = this.game_state.game.add.sprite(human.x - bodyPartOneX, human.y - bodyPartOneY, 'humanparts');
        bodyPartOne.frame = bodyPartOneFrame;
        var bodyPartTwo = this.game_state.game.add.sprite(human.x + bodyPartTwoX, human.y + bodyPartTwoX, 'humanparts');
        bodyPartTwo.frame = bodyPartTwoFrame;

        this.game_state.emitter.flow(500, 30, 2, 100, false);
    };

    return Human;
})();<commit_msg>Random messages<commit_after>var Human = (function() {
    function Human(game_state, x, y) {
        MovingSprite.call(this, game_state, x, y, 'human', 'humans');
        this.speed = 100;
        this.body.allowGravity = false;
		this.game = game_state.game;

        this.game.physics.arcade.enable(this);

        this.framesPerSecond = 10;

        this.moves = ['moveUp', 'moveDown', 'moveLeft', 'moveRight'];

		this.lastMove = null;

        this.devourHuman = function(human, enemy) {
            this.game_state.world_state.devourHuman(human);

            this.makeNastyScreams();
            this.makeNastyEatingNoises();
            this.makeNastyMess(human);

            human.kill();
        };

        this.humanHitsSummon = function(human, summon) {
            if (!summon.fallTween.isRunning && human.alive) {
                var cloneH = this.game_state.game.add.sprite(summon.x, summon.y, 'summon');
                cloneH.anchor.set(0.5);

                var cloneV = this.game_state.game.add.sprite(summon.x, summon.y, 'summon');
                cloneV.anchor.set(0.5);

                this.makeNastyScreams();

                var explosionSpeed = 250;

                this.game_state.game.add.tween(cloneV.scale).to({
                    x: 0.10,
                    y: 10
                }, explosionSpeed, "Expo.easeOut", true, 0);
                this.game_state.game.add.tween(cloneH.scale).to({
                    x: 10,
                    y: 0.10
                }, explosionSpeed, "Expo.easeOut", true, 0);
                this.game.add.tween(cloneH).to({
                    alpha: 0
                }, 250, "Linear", true, 250);
                this.game.add.tween(cloneV).to({
                    alpha: 0
                }, 250, "Linear", true, 250);

                this.game_state.character.addFollower(new Ghost(this.game_state, human.x, human.y));
                this.game_state.world_state.sacrificeHuman(this);

                human.kill();
                summon.kill();
            }
        };

		this.terrainHit = function(human){
			human.forceDirectionChange = true;
		};

        this.animations.add('down', [0, 1, 2, 3, 4, 5], this.framesPerSecond, true);
        this.animations.add('right', [18, 19, 20, 21, 22, 23], this.framesPerSecond, true);
        this.animations.add('up', [12, 13, 14, 15, 16, 17], this.framesPerSecond, true);
        this.animations.add('left', [6, 7, 8, 9, 10, 11], this.framesPerSecond, true);

    };

    Human.prototype = Object.create(MovingSprite.prototype);
    Human.prototype.constructor = Human;

    Human.prototype.update = function() {
         "use strict";
		this.game.physics.arcade.collide(this.game_state.humans, this.game_state.backgroundLayer, this.terrainHit);
		if (this.alive) {
			this.game_state.game.physics.arcade.overlap(this, this.game_state.summonLayer, this.humanHitsSummon, null, this);
			this.game_state.game.physics.arcade.overlap(this, this.game_state.enemy, this.devourHuman, null, this);
			var moveIn = this.lastMove;

			if (this.forceDirectionChange || !this.lastMove || Math.random() > 0.98) {
				this.forceDirectionChange = false;
				moveIn = this.moves[Math.floor(Math.random() * 10) % 4];
			}
			this[moveIn]();
			this.lastMove = moveIn;
			if (this.y > this.game_state.game.height || this.y < 0 || this.x > this.game_state.game.height || this.x < 0) this.destroy();

			this.game_state.emitter.emitX = this.game_state.enemy.x;
	        this.game_state.emitter.emitY = this.game_state.enemy.y;
		}
    };

    Human.prototype.makeNastyScreams = function() {
        this.game_state.screams[this.game.rnd.between(0, this.game_state.screams.length - 1)].play();
    };

    Human.prototype.makeNastyEatingNoises = function() {
        this.game_state.eating[this.game.rnd.between(0, this.game_state.eating.length - 1)].play();
    };

    Human.prototype.makeNastyMess = function(human) {
        var bodyPartOneFrame = Math.floor(Math.random() * 2);
        var bodyPartTwoFrame = Math.floor(Math.random() * 2) + 2;

        // TODO: Refactor when not tired
        var bodyPartOneX = Math.floor(Math.random() * 5);
        var bodyPartOneY = Math.floor(Math.random() * 5);

        var bodyPartTwoX = Math.floor(Math.random() * 5);
        var bodyPartTwoY = Math.floor(Math.random() * 5);

        // TODO: Tween these bad girls
        var bodyPartOne = this.game_state.game.add.sprite(human.x - bodyPartOneX, human.y - bodyPartOneY, 'humanparts');
        bodyPartOne.frame = bodyPartOneFrame;
        var bodyPartTwo = this.game_state.game.add.sprite(human.x + bodyPartTwoX, human.y + bodyPartTwoX, 'humanparts');
        bodyPartTwo.frame = bodyPartTwoFrame;

        this.game_state.emitter.flow(500, 30, 2, 100, false);
    };

    return Human;
})();<|endoftext|>