<commit_before>define(['require', './normalize'], function(req, normalize) {
  var baseUrl = req.toUrl('.');

  var cssAPI = {};

  function compress(css) {
    if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
      try {
        var csso = require.nodeRequire('csso');
        var csslen = css.length;
        css = csso.justDoIt(css);
        console.log('Compressed CSS output to ' + Math.round(css.length / csslen * 100) + '%.');
        return css;
      }
      catch(e) {
        console.log('Compression module not installed. Use "npm install csso -g" to enable.');
        return css;
      }
    }
    console.log('Compression not supported outside of nodejs environments.');
    return css;
  }

  //load file code - stolen from text plugin
  function loadFile(path) {
    if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
      var fs = require.nodeRequire('fs');
      var file = fs.readFileSync(path, 'utf8');
      if (file.indexOf('\uFEFF') === 0)
        return file.substring(1);
      return file;
    }
    else {
      var encoding = "utf-8",
        file = new java.io.File(path),
        lineSeparator = java.lang.System.getProperty("line.separator"),
        input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
        stringBuffer, line,
        content = '';
      try {
        stringBuffer = new java.lang.StringBuffer();
        line = input.readLine();
        if (line && line.length() && line.charAt(0) === 0xfeff)
          line = line.substring(1);
        stringBuffer.append(line);
        while ((line = input.readLine()) !== null) {
          stringBuffer.append(lineSeparator);
          stringBuffer.append(line);
        }
        content = String(stringBuffer.toString());
      }
      finally {
        input.close();
      }
    }
  }

  function saveFile(path, data) {
    if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
      var fs = require.nodeRequire('fs');
      fs.writeFileSync(path, data, 'utf8');
    }
    else {
      var encoding = "utf-8",
        file = new java.io.File(url),
        lineSeparator = java.lang.System.getProperty("line.separator"),
        output = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new java.io.FileOutputStream(file), encoding)),
        stringBuffer, line,
        content = '';

      throw "Rhino support for require-css isn't complete...";
      try {

        output.write(0xffef);
        output.write(data);

        //hmm... help! [Rhino support really isn't an issue but a niceity]
        /* stringBuffer = new java.lang.StringBuffer();

        stringBuffer.append(data);

        while ((line = ))

        output = input.readLine();

        // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
        // http://www.unicode.org/faq/utf_bom.html

        // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
        if (line && line.length() && line.charAt(0) === 0xfeff) {
            // Eat the BOM, since we've already found the encoding on this file,
            // and we plan to concatenating this buffer with others; the BOM should
            // only appear at the top of a file.
            line = line.substring(1);
        }

        stringBuffer.append(line);

        while ((line = input.readLine()) !== null) {
            stringBuffer.append(lineSeparator);
            stringBuffer.append(line);
        }
        //Make sure we return a JavaScript string and not a Java string.
        content = String(stringBuffer.toString()); //String */
      }
      finally {
        output.close();
      }
    }
  }

  //when adding to the link buffer, paths are normalised to the baseUrl
  //when removing from the link buffer, paths are normalised to the output file path
  function escape(content) {
    return content.replace(/(["'\\])/g, '\\$1')
      .replace(/[\f]/g, "\\f")
      .replace(/[\b]/g, "\\b")
      .replace(/[\n]/g, "\\n")
      .replace(/[\t]/g, "\\t")
      .replace(/[\r]/g, "\\r");
  }

  var loadCSS = function(cssId, parse) {
    var fileUrl = cssId;

    if (fileUrl.substr(fileUrl.length - 4, 4) != '.css' && !parse)
      fileUrl += '.css';

    fileUrl = req.toUrl(fileUrl);

    //external URLS don't get added (just like JS requires)
    if (fileUrl.substr(0, 7) == 'http://' || fileUrl.substr(0, 8) == 'https://')
      return;

    //add to the buffer
    var css = loadFile(fileUrl);
    if (parse)
      css = parse(css);

    //normalize all css to the base url - as the common path reference
    //for injection we then only need one normalization from the base url
    css = normalize(css, fileUrl, baseUrl);

    return css;
  }

  var curModule;
  cssAPI.load = function(name, req, load, config) {
    if (config.modules) {
      //run through the module list - the first one without a layer set is the current layer we are in
      //allows to track the current layer number for layer-specific config
      for (var i = 0; i < config.modules.length; i++)
        if (config.modules[i].layer === undefined) {
          curModule = i;
          break;
        }
    }

    //store config
    cssAPI.config = cssAPI.config || config;
    //just return - 'write' calls are made after exclusions so we run loading there
    load();
  }

  cssAPI.normalize = function(name, normalize) {
    if (name.substr(name.length - 1, 1) == '!')
      name = name.substr(0, name.length - 1);
    if (name.substr(name.length - 4, 4) == '.css')
      name = name.substr(0, name.length - 4);
    return normalize(name);
  }

  //list of cssIds included in this layer
  var _layerBuffer = [];

  cssAPI.write = function(pluginName, moduleName, write, extension, parse) {
    //external URLS don't get added (just like JS requires)
    if (moduleName.substr(0, 7) == 'http://' || moduleName.substr(0, 8) == 'https://')
      return;

    _layerBuffer.push(loadCSS(moduleName + (extension ? '.' + extension : ''), parse));

    write.asModule(pluginName + '!' + moduleName, 'define(function(){})');
  }

  cssAPI.onLayerEnd = function(write, data) {
    //separateCSS parameter set either globally or as a layer setting
    var separateCSS = false;
    if (cssAPI.config.separateCSS)
      separateCSS = true;
    if (typeof curModule == 'number')
      separateCSS = cssAPI.config.modules[curModule].separateCSS;
    curModule = null;

    //calculate layer css
    var css = _layerBuffer.join('');

    if (separateCSS) {
      if (typeof console != 'undefined' && console.log)
        console.log('Writing CSS! file: ' + data.name + '\n');

      //calculate the css output path for this layer
      var path = this.config.dir ? this.config.dir + data.name + '.css' : cssAPI.config.out.replace(/\.js$/, '.css');

      //renormalize the css to the output path
      var output = compress(normalize(css, baseUrl, path));

      saveFile(path, output);
    }
    else {
      if (css == '')
        return;
      //write the injection and layer index into the layer
      //prepare the css
      css = escape(compress(css));

      //derive the absolute path for the normalize helper
      var normalizeParts = req.toUrl('css').substr(baseUrl.length - 1).split('/');
      normalizeParts[normalizeParts.length - 1] = 'normalize';
      var normalizeName = normalizeParts.join('/');

      //the code below overrides async require functionality to ensure instant layer css injection
      //it then runs normalization and injection
      //normalization is based on determining the absolute pathname of the html page
      //then determining the absolute baseurl url
      //normalization is then performed from the absolute baseurl to the absolute pathname
      write(''
        + 'for (var c in requirejs.s.contexts) { requirejs.s.contexts[c].nextTick = function(f){f()} } \n'
        + 'require([\'css\', \'' + normalizeName + '\', \'require\'], function(css, normalize, require) { \n'
        + 'var pathname = window.location.pathname.split(\'/\'); \n'
        + 'pathname.pop(); \n'
        + 'pathname = pathname.join(\'/\') + \'/\'; \n'
        + 'var baseUrl = require.toUrl(\'.\'); \n'
        + 'baseUrl = normalize.convertURIBase(baseUrl, pathname, \'/\'); \n'
        + 'css.inject(normalize(\'' + css + '\', baseUrl, pathname)); \n'
        + '}); \n'
        + 'for (var c in requirejs.s.contexts) { requirejs.s.contexts[c].nextTick = requirejs.nextTick; } \n'
      );
    }

    //clear layer buffer for next layer
    _layerBuffer = [];
  }

  return cssAPI;
});
<commit_msg>Rhino optimization load file fix<commit_after>define(['require', './normalize'], function(req, normalize) {
  var baseUrl = req.toUrl('.');

  var cssAPI = {};

  function compress(css) {
    if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
      try {
        var csso = require.nodeRequire('csso');
        var csslen = css.length;
        css = csso.justDoIt(css);
        console.log('Compressed CSS output to ' + Math.round(css.length / csslen * 100) + '%.');
        return css;
      }
      catch(e) {
        console.log('Compression module not installed. Use "npm install csso -g" to enable.');
        return css;
      }
    }
    console.log('Compression not supported outside of nodejs environments.');
    return css;
  }

  //load file code - stolen from text plugin
  function loadFile(path) {
    if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
      var fs = require.nodeRequire('fs');
      var file = fs.readFileSync(path, 'utf8');
      if (file.indexOf('\uFEFF') === 0)
        return file.substring(1);
      return file;
    }
    else {
      var encoding = "utf-8",
        file = new java.io.File(path),
        lineSeparator = java.lang.System.getProperty("line.separator"),
        input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
        stringBuffer, line;
      try {
        stringBuffer = new java.lang.StringBuffer();
        line = input.readLine();
        if (line && line.length() && line.charAt(0) === 0xfeff)
          line = line.substring(1);
        stringBuffer.append(line);
        while ((line = input.readLine()) !== null) {
          stringBuffer.append(lineSeparator).append(line);
        }
        return String(stringBuffer.toString());
      }
      finally {
        input.close();
      }
    }
  }

  function saveFile(path, data) {
    if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
      var fs = require.nodeRequire('fs');
      fs.writeFileSync(path, data, 'utf8');
    }
    else {
      var encoding = "utf-8",
        file = new java.io.File(url),
        lineSeparator = java.lang.System.getProperty("line.separator"),
        output = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new java.io.FileOutputStream(file), encoding)),
        stringBuffer, line,
        content = '';

      throw "Rhino support for require-css isn't complete...";
      try {

        output.write(0xffef);
        output.write(data);

        //hmm... help! [Rhino support really isn't an issue but a niceity]
        /* stringBuffer = new java.lang.StringBuffer();

        stringBuffer.append(data);

        while ((line = ))

        output = input.readLine();

        // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
        // http://www.unicode.org/faq/utf_bom.html

        // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
        if (line && line.length() && line.charAt(0) === 0xfeff) {
            // Eat the BOM, since we've already found the encoding on this file,
            // and we plan to concatenating this buffer with others; the BOM should
            // only appear at the top of a file.
            line = line.substring(1);
        }

        stringBuffer.append(line);

        while ((line = input.readLine()) !== null) {
            stringBuffer.append(lineSeparator);
            stringBuffer.append(line);
        }
        //Make sure we return a JavaScript string and not a Java string.
        content = String(stringBuffer.toString()); //String */
      }
      finally {
        output.close();
      }
    }
  }

  //when adding to the link buffer, paths are normalised to the baseUrl
  //when removing from the link buffer, paths are normalised to the output file path
  function escape(content) {
    return content.replace(/(["'\\])/g, '\\$1')
      .replace(/[\f]/g, "\\f")
      .replace(/[\b]/g, "\\b")
      .replace(/[\n]/g, "\\n")
      .replace(/[\t]/g, "\\t")
      .replace(/[\r]/g, "\\r");
  }

  var loadCSS = function(cssId, parse) {
    var fileUrl = cssId;

    if (fileUrl.substr(fileUrl.length - 4, 4) != '.css' && !parse)
      fileUrl += '.css';

    fileUrl = req.toUrl(fileUrl);

    //external URLS don't get added (just like JS requires)
    if (fileUrl.substr(0, 7) == 'http://' || fileUrl.substr(0, 8) == 'https://')
      return;

    //add to the buffer
    var css = loadFile(fileUrl);
    if (parse)
      css = parse(css);

    //normalize all css to the base url - as the common path reference
    //for injection we then only need one normalization from the base url
    css = normalize(css, fileUrl, baseUrl);

    return css;
  }

  var curModule;
  cssAPI.load = function(name, req, load, config) {
    if (config.modules) {
      //run through the module list - the first one without a layer set is the current layer we are in
      //allows to track the current layer number for layer-specific config
      for (var i = 0; i < config.modules.length; i++)
        if (config.modules[i].layer === undefined) {
          curModule = i;
          break;
        }
    }

    //store config
    cssAPI.config = cssAPI.config || config;
    //just return - 'write' calls are made after exclusions so we run loading there
    load();
  }

  cssAPI.normalize = function(name, normalize) {
    if (name.substr(name.length - 1, 1) == '!')
      name = name.substr(0, name.length - 1);
    if (name.substr(name.length - 4, 4) == '.css')
      name = name.substr(0, name.length - 4);
    return normalize(name);
  }

  //list of cssIds included in this layer
  var _layerBuffer = [];

  cssAPI.write = function(pluginName, moduleName, write, extension, parse) {
    //external URLS don't get added (just like JS requires)
    if (moduleName.substr(0, 7) == 'http://' || moduleName.substr(0, 8) == 'https://')
      return;

    _layerBuffer.push(loadCSS(moduleName + (extension ? '.' + extension : ''), parse));

    write.asModule(pluginName + '!' + moduleName, 'define(function(){})');
  }

  cssAPI.onLayerEnd = function(write, data) {
    //separateCSS parameter set either globally or as a layer setting
    var separateCSS = false;
    if (cssAPI.config.separateCSS)
      separateCSS = true;
    if (typeof curModule == 'number')
      separateCSS = cssAPI.config.modules[curModule].separateCSS;
    curModule = null;

    //calculate layer css
    var css = _layerBuffer.join('');

    if (separateCSS) {
      if (typeof console != 'undefined' && console.log)
        console.log('Writing CSS! file: ' + data.name + '\n');

      //calculate the css output path for this layer
      var path = this.config.dir ? this.config.dir + data.name + '.css' : cssAPI.config.out.replace(/\.js$/, '.css');

      //renormalize the css to the output path
      var output = compress(normalize(css, baseUrl, path));

      saveFile(path, output);
    }
    else {
      if (css == '')
        return;
      //write the injection and layer index into the layer
      //prepare the css
      css = escape(compress(css));

      //derive the absolute path for the normalize helper
      var normalizeParts = req.toUrl('css').substr(baseUrl.length - 1).split('/');
      normalizeParts[normalizeParts.length - 1] = 'normalize';
      var normalizeName = normalizeParts.join('/');

      //the code below overrides async require functionality to ensure instant layer css injection
      //it then runs normalization and injection
      //normalization is based on determining the absolute pathname of the html page
      //then determining the absolute baseurl url
      //normalization is then performed from the absolute baseurl to the absolute pathname
      write(''
        + 'for (var c in requirejs.s.contexts) { requirejs.s.contexts[c].nextTick = function(f){f()} } \n'
        + 'require([\'css\', \'' + normalizeName + '\', \'require\'], function(css, normalize, require) { \n'
        + 'var pathname = window.location.pathname.split(\'/\'); \n'
        + 'pathname.pop(); \n'
        + 'pathname = pathname.join(\'/\') + \'/\'; \n'
        + 'var baseUrl = require.toUrl(\'.\'); \n'
        + 'baseUrl = normalize.convertURIBase(baseUrl, pathname, \'/\'); \n'
        + 'css.inject(normalize(\'' + css + '\', baseUrl, pathname)); \n'
        + '}); \n'
        + 'for (var c in requirejs.s.contexts) { requirejs.s.contexts[c].nextTick = requirejs.nextTick; } \n'
      );
    }

    //clear layer buffer for next layer
    _layerBuffer = [];
  }

  return cssAPI;
});
<|endoftext|>


<commit_before>//Sets up the background page on startup
function onStartUp() {
	browser.storage.local.get()
	.then(function(items) {
		//Checks to see if these settings are in storage, if not create and set the default

	});
}

//Set the defaults
function setDefaults() {
	browser.storage.local.clear()
	.then(function() {
		onStartUp();
	});

}

var indexIncrement = 1;

browser.tabs.onActivated.addListener(function(activeInfo) {
	indexIncrement = 1;
});

function handleMessage(request, sender, sendResponse) {
	browser.tabs.query({currentWindow: true, active: true})
	.then((tabs) => {
		if(request.gesture === "U" && request.targeturl !== undefined) {
			browser.tabs.create({
				url: request.targeturl,
				active: true,
				cookieStoreId: tabs[0].cookieStoreId,
				index: tabs[0].index + indexIncrement
			});
		}

		if(request.gesture === "D" && request.targeturl !== undefined) {
			browser.tabs.create({
				url: request.targeturl,
				active: false,
				cookieStoreId: tabs[0].cookieStoreId,
				index: tabs[0].index + indexIncrement
			});
			indexIncrement++;
		}

		if(request.gesture === "LR") {
			browser.tabs.create({
				active: true
			});
		}

		if(request.gesture === "DR") {
			browser.tabs.remove(tabs[0].id);
		}

		if(request.gesture === "UD") {
			browser.tabs.reload(tabs[0].id, {
				bypassCache: false
			});
		}

		if(request.gesture === "UDU") {
			browser.tabs.reload(tabs[0].id, {
				bypassCache: true
			});
		}

		if(request.gesture === "UD") {
			browser.tabs.reload(tabs[0].id, {
				bypassCache: false
			});
		}

		if(request.gesture === "L") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.history.back()"
			});
		}

		if(request.gesture === "R") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.history.forward()"
			});
		}

		if(request.gesture === "UL") {
			browser.tabs.query({index: tabs[0].index - 1})
			.then(function(tabs) {
				return browser.tabs.update(tabs[0].id, {
					active: true
				}
				);
			});
		}

		if(request.gesture === "UR") {
			browser.tabs.query({index: tabs[0].index + 1})
			.then(function(tabs) {
				return browser.tabs.update(tabs[0].id, {
					active: true
				}
				);
			});
		}

		if(request.gesture === "LU") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.scrollTo(0, 0);"
			});
		}

		if(request.gesture === "LD") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.scrollTo(0, document.body.scrollHeight);"
			});
		}
	});
	return true;
}

browser.runtime.onMessage.addListener(handleMessage);

onStartUp();

<commit_msg>Add the openerTabId to opening tabs<commit_after>//Sets up the background page on startup
function onStartUp() {
	browser.storage.local.get()
	.then(function(items) {
		//Checks to see if these settings are in storage, if not create and set the default

	});
}

//Set the defaults
function setDefaults() {
	browser.storage.local.clear()
	.then(function() {
		onStartUp();
	});

}

var indexIncrement = 1;

browser.tabs.onActivated.addListener(function(activeInfo) {
	indexIncrement = 1;
});

function handleMessage(request, sender, sendResponse) {
	browser.tabs.query({currentWindow: true, active: true})
	.then((tabs) => {
		if(request.gesture === "U" && request.targeturl !== undefined) {
			browser.tabs.create({
				url: request.targeturl,
				active: true,
				cookieStoreId: tabs[0].cookieStoreId,
				index: tabs[0].index + indexIncrement,
				openerTabId: tabs[0].id
			});
		}

		if(request.gesture === "D" && request.targeturl !== undefined) {
			browser.tabs.create({
				url: request.targeturl,
				active: false,
				cookieStoreId: tabs[0].cookieStoreId,
				index: tabs[0].index + indexIncrement,
				openerTabId: tabs[0].id
			});
			indexIncrement++;
		}

		if(request.gesture === "LR") {
			browser.tabs.create({
				active: true
			});
		}

		if(request.gesture === "DR") {
			browser.tabs.remove(tabs[0].id);
		}

		if(request.gesture === "UD") {
			browser.tabs.reload(tabs[0].id, {
				bypassCache: false
			});
		}

		if(request.gesture === "UDU") {
			browser.tabs.reload(tabs[0].id, {
				bypassCache: true
			});
		}

		if(request.gesture === "UD") {
			browser.tabs.reload(tabs[0].id, {
				bypassCache: false
			});
		}

		if(request.gesture === "L") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.history.back()"
			});
		}

		if(request.gesture === "R") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.history.forward()"
			});
		}

		if(request.gesture === "UL") {
			browser.tabs.query({index: tabs[0].index - 1})
			.then(function(tabs) {
				return browser.tabs.update(tabs[0].id, {
					active: true
				}
				);
			});
		}

		if(request.gesture === "UR") {
			browser.tabs.query({index: tabs[0].index + 1})
			.then(function(tabs) {
				return browser.tabs.update(tabs[0].id, {
					active: true
				}
				);
			});
		}

		if(request.gesture === "LU") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.scrollTo(0, 0);"
			});
		}

		if(request.gesture === "LD") {
			browser.tabs.executeScript(tabs[0].id, {
				code: "window.scrollTo(0, document.body.scrollHeight);"
			});
		}
	});
	return true;
}

browser.runtime.onMessage.addListener(handleMessage);

onStartUp();
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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.

/**
 * @fileoverview Background script to handle retrieving information from active
 * tab for reporting and alerting purposes.
 */

goog.module('suspiciousSiteReporter.Background');

const ClientRequest = goog.require('proto.suspiciousSiteReporter.extension.ChromeExtensionClientRequest');
const ReferrerChainEntry = goog.require('proto.suspiciousSiteReporter.extension.ReferrerChainEntry');
const alerts = goog.require('suspiciousSiteReporter.alerts');

/**
 * The API URL used for submitting reports.
 * @define {string} This may be redefined at build time to point at the
 *     prod endpoint.
 */
const API_URL = goog.define('API_URL', 'https://test-safebrowsing.google.com');

/**
 * Converts a data URL to a Uint8Array representation of the screenshot.
 * @param {string} dataUrl URL representation of an image with the following
 *     format: data:[<mediatype>][;base64],<data>
 * @return {!Uint8Array} A Uin8Array representation of the image.
 */
const getIntArrayFromDataUrl = dataUrl => {
  // Separate out the mime component, which comes after the data: prefix and
  // before ;base64. e.g., image/png for screenshot data.
  const mimeString =
      dataUrl.split(',')[0].split(':')[1].split(';')[0];
  // Since the data URL is retrieved from chrome.tabs.captureVisibleTab with
  // the format set to png, verify that the mimeString matches.
  if (mimeString !== 'image/png') {
    throw Error('Screenshot is in incorrect format');
  }
  // Convert base 64 to raw binary data held in a string. The data segment
  // comes after the comma in a data URL.
  const byteString = atob(dataUrl.split(',')[1]);
  // Write the bytes of the string to an ArrayBuffer.
  const intArray =
      new Uint8Array(new ArrayBuffer(byteString.length));
  byteString.split('').forEach((c, i) => {
    intArray[i] = c.charCodeAt(0);
  });
  return intArray;
};

/**
 * Converts a referrer from the extension API into a proto-compatible version.
 * @param {!chrome.safeBrowsingPrivate.ReferrerChainEntry} entry Referrer chain
 *     entry object retrieved from the extension API.
 * @return {!ReferrerChainEntry} A parsed ReferrerChainEntry.
 */
const parseReferrerEntry = entry => {
  const parsedEntry = new ReferrerChainEntry()
                          .setUrl(entry.url)
                          .setMainFrameUrl(entry.mainFrameUrl)
                          .setType(ReferrerChainEntry.URLType[entry.urlType]);
  if (entry.ipAddresses) {
    entry.ipAddresses.forEach((ipAddress) => {
      parsedEntry.addIpAddresses(ipAddress);
    });
  }
  parsedEntry.setReferrerUrl(entry.referrerUrl);
  parsedEntry.setReferrerMainFrameUrl(entry.referrerMainFrameUrl);
  parsedEntry.setIsRetargeting(entry.isRetargeting);
  parsedEntry.setNavigationTimeMsec(entry.navigationTimeMs);
  if (entry.serverRedirectChain) {
    entry.serverRedirectChain.forEach((serverRedirect) => {
      const redirect =
          new ReferrerChainEntry.ServerRedirect().setUrl(serverRedirect.url);
      parsedEntry.addServerRedirectChain(redirect);
    });
  }
  parsedEntry.setNavigationInitiation(
      ReferrerChainEntry.NavigationInitiation[entry.navigationInitiation]);
  parsedEntry.setMaybeLaunchedByExternalApplication(
      entry.maybeLaunchedByExternalApp);
  return parsedEntry;
};

class Background {
  constructor() {
    /** {?Array<string>} A list of suspicious signals on a site.  */
    this.alerts = undefined;
  }

  /**
   * Fetches number of alerts and sets icon badge.
   * @param {!Tab} tab A Chrome Tab instance.
   * @private
   */
  async getAlertBadge_(tab) {
    const alertList = await alerts.computeAlerts(tab.url);
    this.alerts = alertList;

    /**
     * Sets the color of the flag icon.
     * @param {!string} color The color to set the flag. Will be one of orange,
     *     green, or gray.
     * @param {!Tab} tab A Chrome Tab instance.
     */
    const setFlagIconColor = (color, tab) => {
      chrome.browserAction.setIcon({
        path: {
          '16': `images/${color}flag16.png`,
          '48': `images/${color}flag48.png`,
          '128': `images/${color}flag128.png`,
        },
        tabId: tab.id,
      });
    };

    if (alertList.length === 0) {
      chrome.browserAction.setBadgeText({
        text: '',
        tabId: tab.id,
      });
      setFlagIconColor('green', tab);
      return;
    }
    // To reduce noise, show a gray flag if the only signal is the not top
    // site signal. This works because the top site signal is most useful when
    // a website is also flagged for other reasons.
    if (alertList.length === 1 &&
        alertList.includes(alerts.ALERT_MESSAGES['notTopSite'])) {
      chrome.browserAction.setBadgeText({
        text: '',
        tabId: tab.id,
      });
      setFlagIconColor('gray', tab);
    } else {
      chrome.browserAction.setBadgeText({
        text: alertList.length.toString(),
        tabId: tab.id,
      });
      setFlagIconColor('orange', tab);
    }
  }

  /**
   * Submits the report to Safe Browsing.
   * @param {?ClientRequest} data The data to send.
   * @param {string} domain The target domain for submitting the report request.
   * @private
   */
  submitReport_(data, domain) {
    const path = '/safebrowsing/clientreport/crx-report';
    const xhr = new XMLHttpRequest();
    xhr.open('POST', domain.concat(path), true);
    xhr.send(data.serialize());
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          chrome.runtime.sendMessage({'success': true});
        } else {
          chrome.runtime.sendMessage({'error': true});
        }
      }
    };
  }

  /**
   * Listens for a report message from the popup.
   * @param {!Object<string, *>} request Request object.
   * @param {!MessageSender} sender Message sender information.
   * @param {!Function} sendResponse function.
   * @private
   */
  onMessageReceived_(request, sender, sendResponse) {
    if (request['report']) {
      let report = new ClientRequest().setUrl(String(request['url']));
      if (request['screenshotUrl']) {
        report.setScreenshot(
            getIntArrayFromDataUrl(String(request['screenshotUrl'])));
      }
      if (request['domContent']) {
        report.setDom(String(request['domContent']));
      }
      const referrerChain =
          /** @type {!Array<!chrome.safeBrowsingPrivate.ReferrerChainEntry>} */
          (request['referrer']);
      if (referrerChain) {
        referrerChain.forEach((entry) => {
          report.addReferrerChain(parseReferrerEntry(entry));
        });
      }
      this.submitReport_(report, API_URL);
    }
  }

  /**
   * Initializes the extension background page.
   */
  init() {
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
      const requestReceived = /** @type {!Object<string, *>} */ (request);
      this.onMessageReceived_(requestReceived, sender, sendResponse);
    });

    chrome.extension.onConnect.addListener((port) => {
      port.onMessage.addListener((message) => {
        port.postMessage({siteInfo: this.alerts});
      });
    });

    alerts.setTopSitesList();

    /**
     * Sets the browser action and icon for a tab.
     * @param {!Tab} tab A Chrome Tab instance.
     */
    const setBrowserActionAndIcon = (tab) => {
      if (!tab.url || !tab.url.startsWith('http')) {
        chrome.browserAction.disable(tab.id);
      } else {
        chrome.browserAction.enable(tab.id);
        this.getAlertBadge_(tab);
      }
    };
    chrome.tabs.query({active:true}, (tabs) => {
      tabs.forEach((tab) => {
        setBrowserActionAndIcon(tab);
      });
    });
    chrome.tabs.onActivated.addListener((activeTabInfo) => {
      chrome.tabs.get(activeTabInfo.tabId, (tab) => {
        setBrowserActionAndIcon(tab);
      });
    });
    chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
      if (tab.active && (changeInfo.url || changeInfo.status)) {
        setBrowserActionAndIcon(tab);
      }
    });
  }
}

exports = Background;
<commit_msg>Split the data URI only once.<commit_after>// Copyright 2019 Google LLC
//
// 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.

/**
 * @fileoverview Background script to handle retrieving information from active
 * tab for reporting and alerting purposes.
 */

goog.module('suspiciousSiteReporter.Background');

const ClientRequest = goog.require('proto.suspiciousSiteReporter.extension.ChromeExtensionClientRequest');
const ReferrerChainEntry = goog.require('proto.suspiciousSiteReporter.extension.ReferrerChainEntry');
const alerts = goog.require('suspiciousSiteReporter.alerts');

/**
 * The API URL used for submitting reports.
 * @define {string} This may be redefined at build time to point at the
 *     prod endpoint.
 */
const API_URL = goog.define('API_URL', 'https://test-safebrowsing.google.com');

/**
 * Converts a data URL to a Uint8Array representation of the screenshot.
 * @param {string} dataUrl URL representation of an image with the following
 *     format: data:[<mediatype>][;base64],<data>
 * @return {!Uint8Array} A Uin8Array representation of the image.
 */
const getIntArrayFromDataUrl = dataUrl => {
  const urlParts = dataUrl.split(',');
  // Separate out the mime component, which comes after the data: prefix and
  // before ;base64. e.g., image/png for screenshot data.
  const mimeString =
      urlParts[0].split(':')[1].split(';')[0];
  // Since the data URL is retrieved from chrome.tabs.captureVisibleTab with
  // the format set to png, verify that the mimeString matches.
  if (mimeString !== 'image/png') {
    throw Error('Screenshot is in incorrect format');
  }
  // Convert base 64 to raw binary data held in a string. The data segment
  // comes after the comma in a data URL.
  const byteString = atob(urlParts[1]);
  // Write the bytes of the string to an ArrayBuffer.
  const intArray =
      new Uint8Array(new ArrayBuffer(byteString.length));
  byteString.split('').forEach((c, i) => {
    intArray[i] = c.charCodeAt(0);
  });
  return intArray;
};

/**
 * Converts a referrer from the extension API into a proto-compatible version.
 * @param {!chrome.safeBrowsingPrivate.ReferrerChainEntry} entry Referrer chain
 *     entry object retrieved from the extension API.
 * @return {!ReferrerChainEntry} A parsed ReferrerChainEntry.
 */
const parseReferrerEntry = entry => {
  const parsedEntry = new ReferrerChainEntry()
                          .setUrl(entry.url)
                          .setMainFrameUrl(entry.mainFrameUrl)
                          .setType(ReferrerChainEntry.URLType[entry.urlType]);
  if (entry.ipAddresses) {
    entry.ipAddresses.forEach((ipAddress) => {
      parsedEntry.addIpAddresses(ipAddress);
    });
  }
  parsedEntry.setReferrerUrl(entry.referrerUrl);
  parsedEntry.setReferrerMainFrameUrl(entry.referrerMainFrameUrl);
  parsedEntry.setIsRetargeting(entry.isRetargeting);
  parsedEntry.setNavigationTimeMsec(entry.navigationTimeMs);
  if (entry.serverRedirectChain) {
    entry.serverRedirectChain.forEach((serverRedirect) => {
      const redirect =
          new ReferrerChainEntry.ServerRedirect().setUrl(serverRedirect.url);
      parsedEntry.addServerRedirectChain(redirect);
    });
  }
  parsedEntry.setNavigationInitiation(
      ReferrerChainEntry.NavigationInitiation[entry.navigationInitiation]);
  parsedEntry.setMaybeLaunchedByExternalApplication(
      entry.maybeLaunchedByExternalApp);
  return parsedEntry;
};

class Background {
  constructor() {
    /** {?Array<string>} A list of suspicious signals on a site.  */
    this.alerts = undefined;
  }

  /**
   * Fetches number of alerts and sets icon badge.
   * @param {!Tab} tab A Chrome Tab instance.
   * @private
   */
  async getAlertBadge_(tab) {
    const alertList = await alerts.computeAlerts(tab.url);
    this.alerts = alertList;

    /**
     * Sets the color of the flag icon.
     * @param {!string} color The color to set the flag. Will be one of orange,
     *     green, or gray.
     * @param {!Tab} tab A Chrome Tab instance.
     */
    const setFlagIconColor = (color, tab) => {
      chrome.browserAction.setIcon({
        path: {
          '16': `images/${color}flag16.png`,
          '48': `images/${color}flag48.png`,
          '128': `images/${color}flag128.png`,
        },
        tabId: tab.id,
      });
    };

    if (alertList.length === 0) {
      chrome.browserAction.setBadgeText({
        text: '',
        tabId: tab.id,
      });
      setFlagIconColor('green', tab);
      return;
    }
    // To reduce noise, show a gray flag if the only signal is the not top
    // site signal. This works because the top site signal is most useful when
    // a website is also flagged for other reasons.
    if (alertList.length === 1 &&
        alertList.includes(alerts.ALERT_MESSAGES['notTopSite'])) {
      chrome.browserAction.setBadgeText({
        text: '',
        tabId: tab.id,
      });
      setFlagIconColor('gray', tab);
    } else {
      chrome.browserAction.setBadgeText({
        text: alertList.length.toString(),
        tabId: tab.id,
      });
      setFlagIconColor('orange', tab);
    }
  }

  /**
   * Submits the report to Safe Browsing.
   * @param {?ClientRequest} data The data to send.
   * @param {string} domain The target domain for submitting the report request.
   * @private
   */
  submitReport_(data, domain) {
    const path = '/safebrowsing/clientreport/crx-report';
    const xhr = new XMLHttpRequest();
    xhr.open('POST', domain.concat(path), true);
    xhr.send(data.serialize());
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          chrome.runtime.sendMessage({'success': true});
        } else {
          chrome.runtime.sendMessage({'error': true});
        }
      }
    };
  }

  /**
   * Listens for a report message from the popup.
   * @param {!Object<string, *>} request Request object.
   * @param {!MessageSender} sender Message sender information.
   * @param {!Function} sendResponse function.
   * @private
   */
  onMessageReceived_(request, sender, sendResponse) {
    if (request['report']) {
      let report = new ClientRequest().setUrl(String(request['url']));
      if (request['screenshotUrl']) {
        report.setScreenshot(
            getIntArrayFromDataUrl(String(request['screenshotUrl'])));
      }
      if (request['domContent']) {
        report.setDom(String(request['domContent']));
      }
      const referrerChain =
          /** @type {!Array<!chrome.safeBrowsingPrivate.ReferrerChainEntry>} */
          (request['referrer']);
      if (referrerChain) {
        referrerChain.forEach((entry) => {
          report.addReferrerChain(parseReferrerEntry(entry));
        });
      }
      this.submitReport_(report, API_URL);
    }
  }

  /**
   * Initializes the extension background page.
   */
  init() {
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
      const requestReceived = /** @type {!Object<string, *>} */ (request);
      this.onMessageReceived_(requestReceived, sender, sendResponse);
    });

    chrome.extension.onConnect.addListener((port) => {
      port.onMessage.addListener((message) => {
        port.postMessage({siteInfo: this.alerts});
      });
    });

    alerts.setTopSitesList();

    /**
     * Sets the browser action and icon for a tab.
     * @param {!Tab} tab A Chrome Tab instance.
     */
    const setBrowserActionAndIcon = (tab) => {
      if (!tab.url || !tab.url.startsWith('http')) {
        chrome.browserAction.disable(tab.id);
      } else {
        chrome.browserAction.enable(tab.id);
        this.getAlertBadge_(tab);
      }
    };
    chrome.tabs.query({active:true}, (tabs) => {
      tabs.forEach((tab) => {
        setBrowserActionAndIcon(tab);
      });
    });
    chrome.tabs.onActivated.addListener((activeTabInfo) => {
      chrome.tabs.get(activeTabInfo.tabId, (tab) => {
        setBrowserActionAndIcon(tab);
      });
    });
    chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
      if (tab.active && (changeInfo.url || changeInfo.status)) {
        setBrowserActionAndIcon(tab);
      }
    });
  }
}

exports = Background;
<|endoftext|>


<commit_before>import chalk from 'chalk'
import express from 'express'
import path from 'path'

export class Watcher {
	httpServer = null
	lastPort = null
	dirs = null
	server = null
	restarting = false

	constructor(httpServer, dirs) {
		this.httpServer = httpServer

		if(dirs.length === 1 && Array.isArray(dirs[0])) {
			dirs = dirs[0]
		}

		this.dirs = dirs
	}

	async watch() {
		const watcher = require('chokidar').watch(this.dirs)

		watcher.on('all', async () => {
			if(this.restarting) {
				return
			}

			files:
			for(const file of Object.keys(require.cache)) {
				dirs:
				for(const dir of this.dirs) {
					if(file.indexOf(dir) !== 0) {
						continue dirs
					}

					delete require.cache[file]
					continue files
				}
			}

			await this.restart()
		})

		console.log(chalk.yellow('Watching %s'), this.dirs.map(dir => path.relative(process.cwd(), dir)))
		await this.restart()
	}

	async restart() {
		this.restarting = true

		if(!this.server.isNil) {
			console.log(chalk.yellow('Restarting'))
			const oldServer = this.server
			this.server = null

			await oldServer.destroy()
		}

		this.server = await this.serve()
		this.restarting = false
	}

	async serve() {
		let server = null

		try {
			const app = this.httpServer.bootstrapper()
			const port = app.port
			this.lastPort = port

			server = await app.listen(port, () => {
				console.log(chalk.yellow('Listening on port %d'), port)
			})

			server.on('close', () => app.shutdown())
		} catch(err) {
			const codeFrame = err.codeFrame
			delete err.codeFrame

			console.log(chalk.red('Failed to start'), err)
			this.lastPort = this.lastPort || process.env.NODE_PORT

			if(!this.lastPort.isNil) {
				const app = express()
				app.use((req, res) => {
					res.header('Content-Type', 'text/plain')

					if(!codeFrame.isNil) {
						res.send(`${err.message}\n${codeFrame.replace(/\[[0-9]+m/g, '')}`)
					} else {
						res.send(`${err.message}\n${err.stack}`)
					}
				})

				server = await app.listen(this.lastPort)
			}
		}

		if(server.isNil) {
			return null
		}

		const connections = { }

		server.on('connection', connection => {
			const key = `${connection.remoteAddress}:${connection.remotePort}`
			connections[key] = connection
			connection.on('close', () => {
				delete connections[key]
			})
		})

		server.destroy = cb => {
			server.close(cb)

			for(const key of Object.keys(connections)) {
				connections[key].destroy()
			}
		}

		return server
	}

}
<commit_msg>Re-added chokidar.on(ready) to HttpServer/Watcher<commit_after>import chalk from 'chalk'
import express from 'express'
import path from 'path'

export class Watcher {
	httpServer = null
	lastPort = null
	dirs = null
	server = null
	restarting = false

	constructor(httpServer, dirs) {
		this.httpServer = httpServer

		if(dirs.length === 1 && Array.isArray(dirs[0])) {
			dirs = dirs[0]
		}

		this.dirs = dirs
	}

	async watch() {
		const watcher = require('chokidar').watch(this.dirs)

		watcher.on('ready', () => {
			watcher.on('all', async () => {
				if(this.restarting) {
					return
				}

				files:
				for(const file of Object.keys(require.cache)) {
					dirs:
					for(const dir of this.dirs) {
						if(file.indexOf(dir) !== 0) {
							continue dirs
						}

						delete require.cache[file]
						continue files
					}
				}

				await this.restart()
			})
		})

		console.log(chalk.yellow('Watching %s'), this.dirs.map(dir => path.relative(process.cwd(), dir)))
		await this.restart()
	}

	async restart() {
		this.restarting = true

		if(!this.server.isNil) {
			console.log(chalk.yellow('Restarting'))
			const oldServer = this.server
			this.server = null

			await oldServer.destroy()
		}

		this.server = await this.serve()
		this.restarting = false
	}

	async serve() {
		let server = null

		try {
			const app = this.httpServer.bootstrapper()
			const port = app.port
			this.lastPort = port

			server = await app.listen(port, () => {
				console.log(chalk.yellow('Listening on port %d'), port)
			})

			server.on('close', () => app.shutdown())
		} catch(err) {
			const codeFrame = err.codeFrame
			delete err.codeFrame

			console.log(chalk.red('Failed to start'), err)
			this.lastPort = this.lastPort || process.env.NODE_PORT

			if(!this.lastPort.isNil) {
				const app = express()
				app.use((req, res) => {
					res.header('Content-Type', 'text/plain')

					if(!codeFrame.isNil) {
						res.send(`${err.message}\n${codeFrame.replace(/\[[0-9]+m/g, '')}`)
					} else {
						res.send(`${err.message}\n${err.stack}`)
					}
				})

				server = await app.listen(this.lastPort)
			}
		}

		if(server.isNil) {
			return null
		}

		const connections = { }

		server.on('connection', connection => {
			const key = `${connection.remoteAddress}:${connection.remotePort}`
			connections[key] = connection
			connection.on('close', () => {
				delete connections[key]
			})
		})

		server.destroy = cb => {
			server.close(cb)

			for(const key of Object.keys(connections)) {
				connections[key].destroy()
			}
		}

		return server
	}

}
<|endoftext|>


<commit_before>var store = storage('local');

function mingleAPI(path) {
  return store.get('options').then(function (options) {
    var settings = {
      url: `${ options.host }/api/v2${ path }`,
      dataType: 'xml'
    };
    return Promise.resolve($.ajax(settings));
  });
}

function getMingleCardInfo(card) {
  return store.get('options').then(function (options) {
    return mingleAPI(`/projects/${ card.project }/cards/${ card.number }.xml`).then(function (xml) {
      var $xml = $(xml);

      $.extend(card, {
        name: $xml.find('card > name').text(),
        type: $xml.find('card > card_type name').text(),
        url: `${ options.host }/projects/${ card.project }/cards/${ card.number }`,
        labels: []
      });

      return Promise.all([
        addCardLabel(card, $xml),
        addPropertyLabels(card, $xml, options)
      ])
      .then(function () {
        return card;
      });
    });
  });
}

function getPropertyValue($xml, name) {
  var $value = $xml
    .find('card > properties > property name')
    .filter(function () { return $(this).text() === name; })
    .parent()
    .find('value');

  if ($value.find('name').size()) {
    return $value.find('name');
  } else {
    return $value;
  }
}

function getCardColors(card) {
  var key = card.project + '_typeColorMap';

  return store.get(key).then(function (colors) {
    if (colors) return colors;

    return mingleAPI(`/projects/${ card.project }/card_types.xml`).then(function (xml) {
      var $xml = $(xml);
      var colors = $xml
        .find(`card_types > card_type`)
        .map(function () {
          var $node = $(this);
          return {
            name: $node.children('name').text(),
            color: $node.children('color').text() || '#5bb2ef'
          };
        })
        .get()
        .reduce(function (colors, type) {
          colors[type.name] = type.color;
          return colors;
        }, {});

      return store.set(key, colors);
    });
  });
}

function getCardPropertyColors(card) {
  var key = card.project + '_propertyColorMap';

  return store.get(key).then(function (colors) {
    if (colors) return colors;

    var colors = {};

    return mingleAPI(`/projects/${ card.project }/property_definitions.xml`).then(function (xml) {
      $(xml)
        .find('property_definitions > property_definition name').get()
        .forEach(function (node) {
          var $prop = $(node);
          var name = $prop.text();
          var values = $prop.parent().find('property_value_details > property_value').get();
          colors[name] = {};

          values.forEach(function (node) {
            var $node = $(node);
            var value = $node.children('value').text();
            var color = $node.children('color').text();
            colors[name][value] = color || '#5bb2ef';
          });
        });

      return store.set(key, colors);
    });
  });
}

function addCardLabel(card, $xml) {
  return getCardColors(card).then(function (colors) {
    var label = {
      name: 'Mingle',
      value: card.type + ' #' + card.number,
      color: colors[card.type]
    };
    card.labels.push(label);
  });
}

function addPropertyLabel(card, $xml, colors, property) {
  if (!property) return;
  var value = getPropertyValue($xml, property).text();
  var label = {
    name: property,
    value: value,
    color: colors[property][value]
  };
  card.labels.push(label);
}

function addPropertyLabels(card, $xml, options) {
  var properties = options.properties.split(',');
  return getCardPropertyColors(card).then(function (colors) {
    properties.forEach(function (property) {
      addPropertyLabel(card, $xml, colors, $.trim(property));
    });
  });
}

chrome.runtime.onMessage.addListener(function (request, sender, callback) {
  if (request.mingle) {
    getMingleCardInfo(request.mingle).then(callback);
    return true; // make sure we wait for asynchronously executed callback
  }
});
<commit_msg>remove unused param<commit_after>var store = storage('local');

function mingleAPI(path) {
  return store.get('options').then(function (options) {
    var settings = {
      url: `${ options.host }/api/v2${ path }`,
      dataType: 'xml'
    };
    return Promise.resolve($.ajax(settings));
  });
}

function getMingleCardInfo(card) {
  return store.get('options').then(function (options) {
    return mingleAPI(`/projects/${ card.project }/cards/${ card.number }.xml`).then(function (xml) {
      var $xml = $(xml);

      $.extend(card, {
        name: $xml.find('card > name').text(),
        type: $xml.find('card > card_type name').text(),
        url: `${ options.host }/projects/${ card.project }/cards/${ card.number }`,
        labels: []
      });

      return Promise.all([
        addCardLabel(card),
        addPropertyLabels(card, $xml, options)
      ])
      .then(function () {
        return card;
      });
    });
  });
}

function getPropertyValue($xml, name) {
  var $value = $xml
    .find('card > properties > property name')
    .filter(function () { return $(this).text() === name; })
    .parent()
    .find('value');

  if ($value.find('name').size()) {
    return $value.find('name');
  } else {
    return $value;
  }
}

function getCardColors(card) {
  var key = card.project + '_typeColorMap';

  return store.get(key).then(function (colors) {
    if (colors) return colors;

    return mingleAPI(`/projects/${ card.project }/card_types.xml`).then(function (xml) {
      var $xml = $(xml);
      var colors = $xml
        .find(`card_types > card_type`)
        .map(function () {
          var $node = $(this);
          return {
            name: $node.children('name').text(),
            color: $node.children('color').text() || '#5bb2ef'
          };
        })
        .get()
        .reduce(function (colors, type) {
          colors[type.name] = type.color;
          return colors;
        }, {});

      return store.set(key, colors);
    });
  });
}

function getCardPropertyColors(card) {
  var key = card.project + '_propertyColorMap';

  return store.get(key).then(function (colors) {
    if (colors) return colors;

    var colors = {};

    return mingleAPI(`/projects/${ card.project }/property_definitions.xml`).then(function (xml) {
      $(xml)
        .find('property_definitions > property_definition name').get()
        .forEach(function (node) {
          var $prop = $(node);
          var name = $prop.text();
          var values = $prop.parent().find('property_value_details > property_value').get();
          colors[name] = {};

          values.forEach(function (node) {
            var $node = $(node);
            var value = $node.children('value').text();
            var color = $node.children('color').text();
            colors[name][value] = color || '#5bb2ef';
          });
        });

      return store.set(key, colors);
    });
  });
}

function addCardLabel(card) {
  return getCardColors(card).then(function (colors) {
    var label = {
      name: 'Mingle',
      value: card.type + ' #' + card.number,
      color: colors[card.type]
    };
    card.labels.push(label);
  });
}

function addPropertyLabel(card, $xml, colors, property) {
  if (!property) return;
  var value = getPropertyValue($xml, property).text();
  var label = {
    name: property,
    value: value,
    color: colors[property][value]
  };
  card.labels.push(label);
}

function addPropertyLabels(card, $xml, options) {
  var properties = options.properties.split(',');
  return getCardPropertyColors(card).then(function (colors) {
    properties.forEach(function (property) {
      addPropertyLabel(card, $xml, colors, $.trim(property));
    });
  });
}

chrome.runtime.onMessage.addListener(function (request, sender, callback) {
  if (request.mingle) {
    getMingleCardInfo(request.mingle).then(callback);
    return true; // make sure we wait for asynchronously executed callback
  }
});
<|endoftext|>


<commit_before>import { ReduxLoader } from '../../reusable/redux_loader/base'
import { objectAssign, Promise } from '../../reusable/ponyfill'
import Immutable from 'immutable'

const MAX_PAGES = 5

const LoaderState = Immutable.Record({
    queue: Immutable.OrderedSet(),
    inprogress: Immutable.Set(),
    done: Immutable.Set(),
    perLoad: 1
})

export class TabbedReportManager extends ReduxLoader {
    constructor(opts) {
        super(opts)
        this.init_action = opts.prefix + '/init'
        this.queue_action = opts.prefix + '/queue'
        this.start_action = opts.prefix + '/start'
        this.finish_action = opts.prefix + '/finish'
        this.replace_action = opts.prefix + '/replace'
        this.replace_items_action = opts.prefix + '/replace_items'
    }

    extraReducers(opts) {
        let init = {}
        if (opts.report) {
            init.queue = this._queueFromReport(opts.report)
        }

        const defaultState = new LoaderState(init)

        const lsReducer = (state=defaultState, action) => {
            if (action.type.startsWith(opts.prefix)) {
                if (action.type == this.queue_action) {
                    let id = action.payload
                    if (!state.done.has(id) && !state.inprogress.has(id)) {
                        // Push the element to the end of the queue which would be the highest priority
                        state = state.set('queue', state.queue.remove(id).add(id))
                    }
                } else if (action.type == this.start_action) {
                    let inprogress = state.queue.slice(-state.perLoad).toSet()
                    let queue = state.queue.subtract(inprogress)
                    state = state.set('queue', queue).set('inprogress', inprogress)
                } else if (action.type == this.finish_action) {
                    let changes = Immutable.Set(action.payload)
                    console.log('finished loading', changes.toJS())
                    let newData = {
                        done: state.done.union(changes),
                        inprogress: Immutable.Set(),
                        queue: state.queue.subtract(changes),
                        perLoad: Math.min(MAX_PAGES, state.perLoad + 1)
                    }
                    state = state.merge(newData)
                } else if (action.type == this.init_action) {
                    // On initialize, we want the original priorities to stay ahead, so we subtract and re-add them.
                    let result = this._queueFromReport(action.payload)
                    result = result.subtract(state.inprogress).subtract(state.done).subtract(state.queue).union(state.queue)
                    state = state.set('queue', result)
                }
            }
            return state
        }
        return {loader: lsReducer}
    }

    _queueFromReport(input) {
        return Immutable.Map(input)
            .valueSeq()
            .filter((report) => report.type == 'report')
            .sortBy((report) => report.n)
            .map((report) => report.id)
            .toOrderedSet()
    }

    // Separated out because then it's a bit less boilerplate to manage.
    dataReducer(opts) {
        const { defaultState } = opts
        return (state=defaultState, action) => {
            switch (action.type) {
            case this.replace_action:
                return action.payload
            case this.replace_items_action:
                return objectAssign({}, state, action.payload)
            }
            return state
        }
    }

    loadReport(reportId, params) {
        const { findRoot } = this.opts

        return (dispatch, getState) => {
            let data = findRoot(getState()).loader
            if (data.done.has(reportId)) {
                return Promise.resolve(null)
            }
            dispatch({type: this.queue_action, payload: reportId})
            return this.runLoadFlow(dispatch, getState, params)
        }
    }

    runLoadFlow(dispatch, getState, globalParams) {
        const { findRoot } = this.opts
        let getData = () => findRoot(getState()).loader

        let flow = () => {
            let tmpData = getData()
            if (!tmpData.inprogress || !tmpData.inprogress.size && tmpData.queue && tmpData.queue.size) {
                dispatch({type: this.start_action, payload: null})

                let pages = getData().inprogress.toArray()
                let params = objectAssign({pages: pages}, globalParams)
                return dispatch(this.runNetworkAction('load', params, {
                    successHandler: (data) => {
                        let toUpdate = {}
                        pages.forEach((reportId) => {
                            toUpdate[reportId] = data.pages[reportId]
                        })
                        dispatch({type: this.replace_items_action, payload: toUpdate})
                        dispatch({type: this.finish_action, payload: pages})
                        setTimeout(flow, 200)
                    }
                }))
            }
        }
        return flow()
    }

    replaceCollection(value) {
        return {type: this.replace_action, payload: value}
    }

    replaceItem(key, value) {
        return {type: this.replace_items_action, payload: {[key]: value}}
    }

    replaceItems(values) {
        return {type: this.replace_items_action, payload: values}
    }

    init(reportRoot) {
        return {type: this.init_action, payload: reportRoot}
    }
}
<commit_msg>Hack in String.startsWith polyfill for now<commit_after>import { ReduxLoader } from '../../reusable/redux_loader/base'
import { objectAssign, Promise } from '../../reusable/ponyfill'
import Immutable from 'immutable'

const MAX_PAGES = 5

const LoaderState = Immutable.Record({
    queue: Immutable.OrderedSet(),
    inprogress: Immutable.Set(),
    done: Immutable.Set(),
    perLoad: 1
})

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0
        return this.substr(position, searchString.length) === searchString
    }
}

export class TabbedReportManager extends ReduxLoader {
    constructor(opts) {
        super(opts)
        this.init_action = opts.prefix + '/init'
        this.queue_action = opts.prefix + '/queue'
        this.start_action = opts.prefix + '/start'
        this.finish_action = opts.prefix + '/finish'
        this.replace_action = opts.prefix + '/replace'
        this.replace_items_action = opts.prefix + '/replace_items'
    }

    extraReducers(opts) {
        let init = {}
        if (opts.report) {
            init.queue = this._queueFromReport(opts.report)
        }

        const defaultState = new LoaderState(init)

        const lsReducer = (state=defaultState, action) => {
            if (action.type.startsWith(opts.prefix)) {
                if (action.type == this.queue_action) {
                    let id = action.payload
                    if (!state.done.has(id) && !state.inprogress.has(id)) {
                        // Push the element to the end of the queue which would be the highest priority
                        state = state.set('queue', state.queue.remove(id).add(id))
                    }
                } else if (action.type == this.start_action) {
                    let inprogress = state.queue.slice(-state.perLoad).toSet()
                    let queue = state.queue.subtract(inprogress)
                    state = state.set('queue', queue).set('inprogress', inprogress)
                } else if (action.type == this.finish_action) {
                    let changes = Immutable.Set(action.payload)
                    console.log('finished loading', changes.toJS())
                    let newData = {
                        done: state.done.union(changes),
                        inprogress: Immutable.Set(),
                        queue: state.queue.subtract(changes),
                        perLoad: Math.min(MAX_PAGES, state.perLoad + 1)
                    }
                    state = state.merge(newData)
                } else if (action.type == this.init_action) {
                    // On initialize, we want the original priorities to stay ahead, so we subtract and re-add them.
                    let result = this._queueFromReport(action.payload)
                    result = result.subtract(state.inprogress).subtract(state.done).subtract(state.queue).union(state.queue)
                    state = state.set('queue', result)
                }
            }
            return state
        }
        return {loader: lsReducer}
    }

    _queueFromReport(input) {
        return Immutable.Map(input)
            .valueSeq()
            .filter((report) => report.type == 'report')
            .sortBy((report) => report.n)
            .map((report) => report.id)
            .toOrderedSet()
    }

    // Separated out because then it's a bit less boilerplate to manage.
    dataReducer(opts) {
        const { defaultState } = opts
        return (state=defaultState, action) => {
            switch (action.type) {
            case this.replace_action:
                return action.payload
            case this.replace_items_action:
                return objectAssign({}, state, action.payload)
            }
            return state
        }
    }

    loadReport(reportId, params) {
        const { findRoot } = this.opts

        return (dispatch, getState) => {
            let data = findRoot(getState()).loader
            if (data.done.has(reportId)) {
                return Promise.resolve(null)
            }
            dispatch({type: this.queue_action, payload: reportId})
            return this.runLoadFlow(dispatch, getState, params)
        }
    }

    runLoadFlow(dispatch, getState, globalParams) {
        const { findRoot } = this.opts
        let getData = () => findRoot(getState()).loader

        let flow = () => {
            let tmpData = getData()
            if (!tmpData.inprogress || !tmpData.inprogress.size && tmpData.queue && tmpData.queue.size) {
                dispatch({type: this.start_action, payload: null})

                let pages = getData().inprogress.toArray()
                let params = objectAssign({pages: pages}, globalParams)
                return dispatch(this.runNetworkAction('load', params, {
                    successHandler: (data) => {
                        let toUpdate = {}
                        pages.forEach((reportId) => {
                            toUpdate[reportId] = data.pages[reportId]
                        })
                        dispatch({type: this.replace_items_action, payload: toUpdate})
                        dispatch({type: this.finish_action, payload: pages})
                        setTimeout(flow, 200)
                    }
                }))
            }
        }
        return flow()
    }

    replaceCollection(value) {
        return {type: this.replace_action, payload: value}
    }

    replaceItem(key, value) {
        return {type: this.replace_items_action, payload: {[key]: value}}
    }

    replaceItems(values) {
        return {type: this.replace_items_action, payload: values}
    }

    init(reportRoot) {
        return {type: this.init_action, payload: reportRoot}
    }
}
<|endoftext|>


<commit_before>define( [
            'dojo/_base/declare',
            'dojo/_base/array',
            'dojo/_base/Deferred',
            'dojo/store/JsonRest',
            'dojo/store/util/QueryResults',
            'JBrowse/Digest/Crc32'
        ],
        function(
            declare,
            array,
            Deferred,
            dojoJSONRest,
            QueryResults,
            digest
        ) {

return declare( null, {

    constructor: function( args ) {
        // make sure url has a trailing slash
        var url = /\/$/.test( args.url ) ? args.url : args.url + '/';
        this.bucketStore = new dojoJSONRest({
            target: url
        });

        this.meta = {};

        this.browser = args.browser;

        // this.ready is a Deferred that will be resolved when we have
        // read the meta.json file with the params of this hashstore
        this.ready = this._readMeta();
    },

    _readMeta: function() {
        var thisB = this;
        return this.bucketStore.get( 'meta.json' )
            .then( function( meta ) {
                dojo.mixin( thisB.meta, meta || {} );
                thisB.meta.hash_hex_characters = Math.ceil( thisB.meta.hash_bits / 4 );
            });
    },

    query: function( query, options ) {
        return this.get( (query.name || '').toString() )
                   .then( function( value ) {
                              return QueryResults( (value||{}).exact || [] );
                          });
    },

    get: function( key ) {
        return this._getBucket(key)
                   .then( function( bucket ) {
                        return bucket[key];
                    });
    },

    _getBucket: function( key ) {
        var thisB = this;
        var bucketP = new Deferred();
        this.ready.then( function() {
            var bucketIdent = thisB._hash( key );
            thisB.bucketStore.get( thisB._hexToDirPath( bucketIdent ) )
                 .then(function(d) { bucketP.resolve(d); } );
        });

        return bucketP;
    },

    _hexToDirPath: function( hex ) {
        // zero-pad the hex string to be 8 chars if necessary
        while( hex.length < 8 )
            hex = '0'+hex;
        hex = hex.substr( 8-this.meta.hash_hex_characters );
        var dirpath = [];
        for( var i = 0; i < hex.length; i += 3 ) {
            dirpath.push( hex.substring( i, i+3 ) );
        }
        return dirpath.join('/') + '.json' + ( this.meta.compress ? 'z' : '' );
    },

    _hash: function( data ) {
        return digest.objectFingerprint( data )
                     .toString(16)
                     .toLowerCase()
                     .replace('-','n');
    },

    getIdentity: function( object ) {
        return object.id;
    }
});
});<commit_msg>bugfix to JBrowse/Store/Hash stupid use of deferreds<commit_after>define( [
            'dojo/_base/declare',
            'dojo/_base/array',
            'dojo/store/JsonRest',
            'dojo/store/util/QueryResults',
            'JBrowse/Digest/Crc32'
        ],
        function(
            declare,
            array,
            dojoJSONRest,
            QueryResults,
            digest
        ) {

return declare( null, {

    constructor: function( args ) {
        // make sure url has a trailing slash
        var url = /\/$/.test( args.url ) ? args.url : args.url + '/';
        this.bucketStore = new dojoJSONRest({
            target: url
        });

        this.meta = {};

        this.browser = args.browser;

        // this.ready is a Deferred that will be resolved when we have
        // read the meta.json file with the params of this hashstore
        this.ready = this._readMeta();
    },

    _readMeta: function() {
        var thisB = this;
        return this.bucketStore.get( 'meta.json' )
            .then( function( meta ) {
                dojo.mixin( thisB.meta, meta || {} );
                thisB.meta.hash_hex_characters = Math.ceil( thisB.meta.hash_bits / 4 );
            });
    },

    query: function( query, options ) {
        return this.get( (query.name || '').toString() )
                   .then( function( value ) {
                              return QueryResults( (value||{}).exact || [] );
                          });
    },

    get: function( key ) {
        return this._getBucket(key)
                   .then( function( bucket ) {
                        return bucket[key];
                    });
    },

    _getBucket: function( key ) {
        var thisB = this;
        return this.ready
            .then( function() {
                       var bucketIdent = thisB._hash( key );
                       return thisB.bucketStore
                           .get( thisB._hexToDirPath( bucketIdent ) );
                   });
    },

    _hexToDirPath: function( hex ) {
        // zero-pad the hex string to be 8 chars if necessary
        while( hex.length < 8 )
            hex = '0'+hex;
        hex = hex.substr( 8-this.meta.hash_hex_characters );
        var dirpath = [];
        for( var i = 0; i < hex.length; i += 3 ) {
            dirpath.push( hex.substring( i, i+3 ) );
        }
        return dirpath.join('/') + '.json' + ( this.meta.compress ? 'z' : '' );
    },

    _hash: function( data ) {
        return digest.objectFingerprint( data )
                     .toString(16)
                     .toLowerCase()
                     .replace('-','n');
    },

    getIdentity: function( object ) {
        return object.id;
    }
});
});<|endoftext|>


<commit_before>(function () {
  var ns = $.namespace('pskl.controller.dialogs.importwizard.steps');

  ns.InsertLocation = function () {
    this.superclass.constructor.apply(this, arguments);
  };

  ns.InsertLocation.MODES = {
    ADD : 'add',
    INSERT : 'insert'
  };

  pskl.utils.inherit(ns.InsertLocation, ns.AbstractImportStep);

  ns.InsertLocation.prototype.init = function () {
    this.superclass.init.call(this);
    this.framePreview = this.container.querySelector('.insert-frame-preview');
    this.currentPiskelFramePickerWidget = new pskl.widgets.FramePicker(
      this.piskelController.getPiskel(), this.framePreview);
    this.currentPiskelFramePickerWidget.init();

    var currentFrameIndex = this.piskelController.getCurrentFrameIndex();
    this.currentPiskelFramePickerWidget.setFrameIndex(currentFrameIndex + 1);
    this.currentPiskelFramePickerWidget.setFirstFrameIndex(0);

    this.insertModeContainer = this.container.querySelector('.insert-mode-container');
    this.addEventListener(this.insertModeContainer, 'change', this.onInsertModeChange_);
    this.mergeData.insertMode = ns.InsertLocation.MODES.ADD;
  };

  ns.InsertLocation.prototype.onInsertModeChange_  = function () {
    var value = this.insertModeContainer.querySelector(':checked').value;
    this.mergeData.insertMode = value;

    if (this.mergeData.insertMode === ns.InsertLocation.MODES.ADD) {
      this.currentPiskelFramePickerWidget.setFirstFrameIndex(0);
    } else {
      this.currentPiskelFramePickerWidget.setFirstFrameIndex(1);
    }
  };

  ns.InsertLocation.prototype.onShow = function () {
    // Nothing to do here!
    this.superclass.onShow.call(this);
  };

  ns.InsertLocation.prototype.onNextClick = function () {
    var insertIndex = this.currentPiskelFramePickerWidget.getFrameIndex();
    this.mergeData.insertIndex = insertIndex;
    this.superclass.onNextClick.call(this);
  };

  ns.InsertLocation.prototype.destroy = function () {
    this.currentPiskelFramePickerWidget.destroy();
    this.superclass.destroy.call(this);
  };
})();
<commit_msg>initialize insert-location frame-picker on show()<commit_after>(function () {
  var ns = $.namespace('pskl.controller.dialogs.importwizard.steps');

  ns.InsertLocation = function () {
    this.superclass.constructor.apply(this, arguments);
  };

  ns.InsertLocation.MODES = {
    ADD : 'add',
    INSERT : 'insert'
  };

  pskl.utils.inherit(ns.InsertLocation, ns.AbstractImportStep);

  ns.InsertLocation.prototype.init = function () {
    this.superclass.init.call(this);
    this.framePreview = this.container.querySelector('.insert-frame-preview');
    this.currentPiskelFramePickerWidget = new pskl.widgets.FramePicker(
      this.piskelController.getPiskel(), this.framePreview);

    this.insertModeContainer = this.container.querySelector('.insert-mode-container');
    this.addEventListener(this.insertModeContainer, 'change', this.onInsertModeChange_);
    this.mergeData.insertMode = ns.InsertLocation.MODES.ADD;
  };

  ns.InsertLocation.prototype.onInsertModeChange_  = function () {
    var value = this.insertModeContainer.querySelector(':checked').value;
    this.mergeData.insertMode = value;

    if (this.mergeData.insertMode === ns.InsertLocation.MODES.ADD) {
      this.currentPiskelFramePickerWidget.setFirstFrameIndex(0);
    } else {
      this.currentPiskelFramePickerWidget.setFirstFrameIndex(1);
    }
  };

  ns.InsertLocation.prototype.onShow = function () {
    this.currentPiskelFramePickerWidget.init();
    var currentFrameIndex = this.piskelController.getCurrentFrameIndex();
    this.currentPiskelFramePickerWidget.setFrameIndex(currentFrameIndex + 1);
    this.currentPiskelFramePickerWidget.setFirstFrameIndex(0);

    this.superclass.onShow.call(this);
  };

  ns.InsertLocation.prototype.onNextClick = function () {
    var insertIndex = this.currentPiskelFramePickerWidget.getFrameIndex();
    this.mergeData.insertIndex = insertIndex;
    this.superclass.onNextClick.call(this);
  };

  ns.InsertLocation.prototype.destroy = function () {
    this.currentPiskelFramePickerWidget.destroy();
    this.superclass.destroy.call(this);
  };
})();
<|endoftext|>


<commit_before>import angular from 'angular';
import _ from 'underscore';
import '../materials-exchange/materials-exchange.scss';

angular.module('dimApp').controller('dimMaterialsExchangeCtrl', MaterialsController);

function MaterialsController(dimDefinitions, dimItemService, dimStoreService, $state) {
  if (!$featureFlags.materialsExchangeEnabled) {
    $state.go('inventory');
    return;
  }

  const vm = this;

  vm.items = {};
  dimDefinitions.getDefinitions().then((defs) => {
    vm.items[3159615086] = defs.InventoryItem.get(3159615086);
  });

  vm.repPool = {};
  vm.newRank = 0;
  vm.newExperience = 0;

  vm.factions = [
    // 174528503, eris breaks things atm
    3871980777,
    1424722124,
    2778795080
  ];

  vm.characters = dimStoreService.getStores()
    .filter((character) => {
      return !character.isVault;
    })
    .map((item) => {
      const background = item.background;
      const icon = item.icon;
      const className = item.className;
      const genderRace = item.genderRace;
      const factions = item.progression.progressions.filter((faction) => {
        return vm.factions.includes(faction.hash);
      }).reduce((map, obj) => {
        map[obj.hash] = obj;
        return map;
      }, {});
      return { background, icon, className, genderRace, factions };
    });

  if (vm.characters.length === 0) {
    $state.go('inventory');
    return;
  }

  vm.activeCharacter = vm.characters[0];
  vm.activeFaction = vm.activeCharacter.factions[1424722124];
  vm.setActiveFaction = function(hash) {
    vm.activeFaction = vm.activeCharacter.factions[hash];
    updateRanks();
  };

  vm.setActiveCharacter = function(character) {
    vm.activeCharacter = character;
    vm.setActiveFaction(vm.activeFaction.hash);
  };

  vm.toggleItem = function(item) {
    if (vm.repPool[item.hash]) {
      delete vm.repPool[item.hash];
    } else {
      vm.repPool[item.hash] = vm.calculateRep(item);
    }
    updateRanks();
  };

  function updateRanks() {
    // rank 1 = 1500
    // rank 2 = 2000
    // rank 3+ = 2500
    let total = 0;

    for (const key in vm.repPool) {
      total = total + vm.repPool[key];
    }

    const totalRank = total + vm.activeFaction.progressToNextLevel;
    vm.newRank = Math.floor((totalRank) / 2500) + vm.activeFaction.level;
    vm.newExperience = (totalRank % 2500);
  }

  const materialsHashes = [
    211861343,  // heavy ammo synth
    928169143,  // special ammo synth
    937555249,  // motes of light
    1542293174, // armor materials
    1898539128  // weapon parts
  ];

  const planataryMatsHashes = [
    1797491610, // Helium Filaments
    2882093969, // Spin Metal
    3242866270, // Relic Iron
    2254123540, // Spirit Bloom
    3164836592 // Wormspore
  ];

  const xurMatsHashes = [
    1738186005, // strange coins
    211861343  // heavy ammo synth
  ];

  const variksMatsHashes = [
    3783295803, // Ether Seeds
    211861343  // heavy ammo synth
  ];

  const erisMatsHashes = [
    1043138475, // black wax idol
    211861343  // heavy ammo synth
  ];

  const gunSmithMatsHashes = [
    1898539128  // weapon parts
  ];

  vm.glimmer = dimStoreService.getVault().glimmer;
  vm.xurMats = mapXurItems(xurMatsHashes);
  vm.planataryMats = mapItems(planataryMatsHashes);
  vm.materials = mapItems(materialsHashes);
  vm.variksMats = mapVariksItems(variksMatsHashes);
  vm.erisMats = mapErisItems(erisMatsHashes);
  vm.gunSmithMats = mapGunsmithItems(gunSmithMatsHashes);

  function mapItems(hashes) {
    return hashes.map((hash) => {
      const ret = angular.copy(dimStoreService.getItemAcrossStores({
        hash: hash
      }));
      if (ret) {
        ret.amount = 0;
        dimStoreService.getStores().forEach((s) => {
          ret.amount += s.amountOfItem(ret);
        });
      }
      return ret;
    }).filter((item) => !_.isUndefined(item));
  }

  function mapXurItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[1] && mappedItems[0] && mappedItems[0].amount) {
      mappedItems[1].amount = mappedItems[0].amount * 3;
    }
    return mappedItems;
  }

  function mapGunsmithItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[0]) {
      mappedItems[0].amount = Math.floor(vm.glimmer / 1250) * 25;
    }
    return mappedItems;
  }

  function mapVariksItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[1] && mappedItems[0] && mappedItems[0].amount) {
      mappedItems[1].amount = mappedItems[0].amount;
    }
    return mappedItems;
  }

  function mapErisItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[1] && mappedItems[0] && mappedItems[0].amount) {
      mappedItems[1].amount = mappedItems[0].amount;
    }
    return mappedItems;
  }

  vm.calculateRep = function(item) {
    let rep = 0;
    if (item && item.hash) {
      switch (item.hash) {
      case 211861343: // heavy ammo synth
        rep = Math.floor(item.amount * 25);
        break;
      case 937555249: // motes of light
        rep = Math.floor(item.amount / 5) * 100;
        break;
      case 928169143: // special ammo synth
        rep = Math.floor(item.amount / 4) * 25;
        break;
      case 1542293174: // armor materials
      case 1898539128: // weapon parts
      case 1797491610: // Helium Filaments
      case 2882093969: // Spin Metal
      case 3242866270: // Relic Iron
      case 2254123540: // Spirit Bloom
      case 3164836592: // Wormspore
        rep = Math.floor(item.amount / 25) * 50;
        break;
      default:
        return '?';
      }
    }
    return rep;
  };
}
<commit_msg>Remove unused parameter<commit_after>import angular from 'angular';
import _ from 'underscore';
import '../materials-exchange/materials-exchange.scss';

angular.module('dimApp').controller('dimMaterialsExchangeCtrl', MaterialsController);

function MaterialsController(dimDefinitions, dimStoreService, $state) {
  if (!$featureFlags.materialsExchangeEnabled) {
    $state.go('inventory');
    return;
  }

  const vm = this;

  vm.items = {};
  dimDefinitions.getDefinitions().then((defs) => {
    vm.items[3159615086] = defs.InventoryItem.get(3159615086);
  });

  vm.repPool = {};
  vm.newRank = 0;
  vm.newExperience = 0;

  vm.factions = [
    // 174528503, eris breaks things atm
    3871980777,
    1424722124,
    2778795080
  ];

  vm.characters = dimStoreService.getStores()
    .filter((character) => {
      return !character.isVault;
    })
    .map((item) => {
      const background = item.background;
      const icon = item.icon;
      const className = item.className;
      const genderRace = item.genderRace;
      const factions = item.progression.progressions.filter((faction) => {
        return vm.factions.includes(faction.hash);
      }).reduce((map, obj) => {
        map[obj.hash] = obj;
        return map;
      }, {});
      return { background, icon, className, genderRace, factions };
    });

  if (vm.characters.length === 0) {
    $state.go('inventory');
    return;
  }

  vm.activeCharacter = vm.characters[0];
  vm.activeFaction = vm.activeCharacter.factions[1424722124];
  vm.setActiveFaction = function(hash) {
    vm.activeFaction = vm.activeCharacter.factions[hash];
    updateRanks();
  };

  vm.setActiveCharacter = function(character) {
    vm.activeCharacter = character;
    vm.setActiveFaction(vm.activeFaction.hash);
  };

  vm.toggleItem = function(item) {
    if (vm.repPool[item.hash]) {
      delete vm.repPool[item.hash];
    } else {
      vm.repPool[item.hash] = vm.calculateRep(item);
    }
    updateRanks();
  };

  function updateRanks() {
    // rank 1 = 1500
    // rank 2 = 2000
    // rank 3+ = 2500
    let total = 0;

    for (const key in vm.repPool) {
      total = total + vm.repPool[key];
    }

    const totalRank = total + vm.activeFaction.progressToNextLevel;
    vm.newRank = Math.floor((totalRank) / 2500) + vm.activeFaction.level;
    vm.newExperience = (totalRank % 2500);
  }

  const materialsHashes = [
    211861343,  // heavy ammo synth
    928169143,  // special ammo synth
    937555249,  // motes of light
    1542293174, // armor materials
    1898539128  // weapon parts
  ];

  const planataryMatsHashes = [
    1797491610, // Helium Filaments
    2882093969, // Spin Metal
    3242866270, // Relic Iron
    2254123540, // Spirit Bloom
    3164836592 // Wormspore
  ];

  const xurMatsHashes = [
    1738186005, // strange coins
    211861343  // heavy ammo synth
  ];

  const variksMatsHashes = [
    3783295803, // Ether Seeds
    211861343  // heavy ammo synth
  ];

  const erisMatsHashes = [
    1043138475, // black wax idol
    211861343  // heavy ammo synth
  ];

  const gunSmithMatsHashes = [
    1898539128  // weapon parts
  ];

  vm.glimmer = dimStoreService.getVault().glimmer;
  vm.xurMats = mapXurItems(xurMatsHashes);
  vm.planataryMats = mapItems(planataryMatsHashes);
  vm.materials = mapItems(materialsHashes);
  vm.variksMats = mapVariksItems(variksMatsHashes);
  vm.erisMats = mapErisItems(erisMatsHashes);
  vm.gunSmithMats = mapGunsmithItems(gunSmithMatsHashes);

  function mapItems(hashes) {
    return hashes.map((hash) => {
      const ret = angular.copy(dimStoreService.getItemAcrossStores({
        hash: hash
      }));
      if (ret) {
        ret.amount = 0;
        dimStoreService.getStores().forEach((s) => {
          ret.amount += s.amountOfItem(ret);
        });
      }
      return ret;
    }).filter((item) => !_.isUndefined(item));
  }

  function mapXurItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[1] && mappedItems[0] && mappedItems[0].amount) {
      mappedItems[1].amount = mappedItems[0].amount * 3;
    }
    return mappedItems;
  }

  function mapGunsmithItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[0]) {
      mappedItems[0].amount = Math.floor(vm.glimmer / 1250) * 25;
    }
    return mappedItems;
  }

  function mapVariksItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[1] && mappedItems[0] && mappedItems[0].amount) {
      mappedItems[1].amount = mappedItems[0].amount;
    }
    return mappedItems;
  }

  function mapErisItems(hashes) {
    const mappedItems = mapItems(hashes);
    if (mappedItems[1] && mappedItems[0] && mappedItems[0].amount) {
      mappedItems[1].amount = mappedItems[0].amount;
    }
    return mappedItems;
  }

  vm.calculateRep = function(item) {
    let rep = 0;
    if (item && item.hash) {
      switch (item.hash) {
      case 211861343: // heavy ammo synth
        rep = Math.floor(item.amount * 25);
        break;
      case 937555249: // motes of light
        rep = Math.floor(item.amount / 5) * 100;
        break;
      case 928169143: // special ammo synth
        rep = Math.floor(item.amount / 4) * 25;
        break;
      case 1542293174: // armor materials
      case 1898539128: // weapon parts
      case 1797491610: // Helium Filaments
      case 2882093969: // Spin Metal
      case 3242866270: // Relic Iron
      case 2254123540: // Spirit Bloom
      case 3164836592: // Wormspore
        rep = Math.floor(item.amount / 25) * 50;
        break;
      default:
        return '?';
      }
    }
    return rep;
  };
}
<|endoftext|>