<commit_before>/*
 * ext-foreignobject.js
 *
 * Licensed under the Apache License, Version 2
 *
 * Copyright(c) 2010 Jacques Distler
 * Copyright(c) 2010 Alexis Deveria
 *
 */

$(function() {
	svgCanvas.addExtension("foreignObject", function(S) {
		var svgcontent = S.svgcontent,
			addElem = S.addSvgElementFromJson,
			selElems,
			svgns = "http://www.w3.org/2000/svg",
			xlinkns = "http://www.w3.org/1999/xlink",
			xmlns = "http://www.w3.org/XML/1998/namespace",
			xmlnsns = "http://www.w3.org/2000/xmlns/",
			se_ns = "http://svg-edit.googlecode.com",
			htmlns = "http://www.w3.org/1999/xhtml",
			mathns = "http://www.w3.org/1998/Math/MathML",
			editingforeign = false,
			svgdoc = S.svgroot.parentNode.ownerDocument,
			started,
			newFO;

		var properlySourceSizeTextArea = function(){
			// TODO: remove magic numbers here and get values from CSS
			var height = $('#svg_source_container').height() - 80;
			$('#svg_source_textarea').css('height', height);
		};

		function showPanel(on) {
			var fc_rules = $('#fc_rules');
			if(!fc_rules.length) {
				fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
			}
			fc_rules.text(!on?"":" #tool_topath { display: none !important; }");
			$('#foreignObject_panel').toggle(on);
		}

		function toggleSourceButtons(on) {
			$('#tool_source_save, #tool_source_cancel').toggle(!on);
			$('#foreign_save, #foreign_cancel').toggle(on);
		}

		// Function: setForeignString(xmlString, elt)
		// This function sets the content of element elt to the input XML.
		//
		// Parameters:
		// xmlString - The XML text.
		// elt - the parent element to append to
		//
		// Returns:
		// This function returns false if the set was unsuccessful, true otherwise.
		function setForeignString(xmlString) {
			var elt = selElems[0];
			try {
				// convert string into XML document
				var newDoc = Utils.text2xml('<svg xmlns="'+svgns+'" xmlns:xlink="'+xlinkns+'">'+xmlString+'</svg>');
				// run it through our sanitizer to remove anything we do not support
				S.sanitizeSvg(newDoc.documentElement);
				elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
				S.call("changed", [elt]);
				svgCanvas.clearSelection();
			} catch(e) {
				console.log(e);
				return false;
			}

			return true;
		};

		function showForeignEditor() {
			var elt = selElems[0];
			if (!elt || editingforeign) return;
			editingforeign = true;
			toggleSourceButtons(true);
			elt.removeAttribute('fill');

			var str = S.svgToString(elt, 0);
			$('#svg_source_textarea').val(str);
			$('#svg_source_editor').fadeIn();
			properlySourceSizeTextArea();
			$('#svg_source_textarea').focus();
		}

		function setAttr(attr, val) {
			svgCanvas.changeSelectedAttribute(attr, val);
			S.call("changed", selElems);
		}

		return {
			name: "foreignObject",
			svgicons: "extensions/foreignobject-icons.xml",
			buttons: [{
				id: "tool_foreign",
				type: "mode",
				title: "Foreign Object Tool",
				events: {
					'click': function() {
						svgCanvas.setMode('foreign')
					}
				}
			},{
				id: "edit_foreign",
				type: "context",
				panel: "foreignObject_panel",
				title: "Edit ForeignObject Content",
				events: {
					'click': function() {
						showForeignEditor();
					}
				}
			}],

			context_tools: [{
				type: "input",
				panel: "foreignObject_panel",
				title: "Change foreignObject's width",
				id: "foreign_width",
				label: "w",
				size: 3,
				events: {
					change: function() {
						setAttr('width', this.value);
					}
				}
			},{
				type: "input",
				panel: "foreignObject_panel",
				title: "Change foreignObject's height",
				id: "foreign_height",
				label: "h",
				events: {
					change: function() {
						setAttr('height', this.value);
					}
				}
			}, {
				type: "input",
				panel: "foreignObject_panel",
				title: "Change foreignObject's height",
				id: "foreign_font_size",
				label: "font-size",
				size: 2,
				defval: 16,
				events: {
					change: function() {
						setAttr('font-size', this.value);
					}
				}
			}

			],
			callback: function() {
				$('#foreignObject_panel').hide();

				var endChanges = function() {
					$('#svg_source_editor').hide();
					editingforeign = false;
					$('#svg_source_textarea').blur();
					toggleSourceButtons(false);
				}

				// TODO: Needs to be done after orig icon loads
				setTimeout(function() {
					// Create source save/cancel buttons
					var save = $('#tool_source_save').clone()
						.hide().attr('id', 'foreign_save').unbind()
						.appendTo("#tool_source_back").click(function() {

							if (!editingforeign) return;

							if (!setForeignString($('#svg_source_textarea').val())) {
								$.confirm("Errors found. Revert to original?", function(ok) {
									if(!ok) return false;
									endChanges();
								});
							} else {
								endChanges();
							}
							// setSelectMode();
						});

					var cancel = $('#tool_source_cancel').clone()
						.hide().attr('id', 'foreign_cancel').unbind()
						.appendTo("#tool_source_back").click(function() {
							endChanges();
						});

				}, 3000);
			},
			mouseDown: function(opts) {
				var e = opts.event;

				if(svgCanvas.getMode() == "foreign") {

					started = true;
					newFO = S.addSvgElementFromJson({
						"element": "foreignObject",
						"attr": {
							"x": opts.start_x,
							"y": opts.start_y,
							"id": S.getNextId(),
							"font-size": 16, //cur_text.font_size,
							"width": "24",
							"height": "24",
							"style": "pointer-events:inherit"
						}
					});
					var m = svgdoc.createElementNS(mathns, 'math');
					m.setAttributeNS(xmlnsns, 'xmlns', mathns);
					m.setAttribute('display', 'inline');
					var mi = svgdoc.createElementNS(mathns, 'mo');
					mi.textContent = "\u03A6";
					m.appendChild(mi);
					newFO.appendChild(m);
					return {
						started: true
					}
				}
			},
			mouseUp: function(opts) {
				var e = opts.event;
				if(svgCanvas.getMode() == "foreign" && started) {
					var attrs = $(newFO).attr(["width", "height"]);
					keep = (attrs.width != 0 || attrs.height != 0);
					svgCanvas.addToSelection([newFO], true);

					return {
						keep: keep,
						element: newFO
					}

				}

			},
			selectedChanged: function(opts) {
				// Use this to update the current selected elements
				selElems = opts.elems;

				var i = selElems.length;

				while(i--) {
					var elem = selElems[i];
					if(elem && elem.tagName == "foreignObject") {
						if(opts.selectedElement && !opts.multiselected) {
							$('#foreign_font_size').val(elem.getAttribute("font-size"));
							$('#foreign_width').val(elem.getAttribute("width"));
							$('#foreign_height').val(elem.getAttribute("height"));

							showPanel(true);
						} else {
							showPanel(false);
						}
					} else {
						showPanel(false);
					}
				}
			},
			elementChanged: function(opts) {
				var elem = opts.elems[0];
			}
		};
	});
});
<commit_msg>Slightly nice placeholder content for foreignObject.<commit_after>/*
 * ext-foreignobject.js
 *
 * Licensed under the Apache License, Version 2
 *
 * Copyright(c) 2010 Jacques Distler
 * Copyright(c) 2010 Alexis Deveria
 *
 */

$(function() {
	svgCanvas.addExtension("foreignObject", function(S) {
		var svgcontent = S.svgcontent,
			addElem = S.addSvgElementFromJson,
			selElems,
			svgns = "http://www.w3.org/2000/svg",
			xlinkns = "http://www.w3.org/1999/xlink",
			xmlns = "http://www.w3.org/XML/1998/namespace",
			xmlnsns = "http://www.w3.org/2000/xmlns/",
			se_ns = "http://svg-edit.googlecode.com",
			htmlns = "http://www.w3.org/1999/xhtml",
			mathns = "http://www.w3.org/1998/Math/MathML",
			editingforeign = false,
			svgdoc = S.svgroot.parentNode.ownerDocument,
			started,
			newFO;

		var properlySourceSizeTextArea = function(){
			// TODO: remove magic numbers here and get values from CSS
			var height = $('#svg_source_container').height() - 80;
			$('#svg_source_textarea').css('height', height);
		};

		function showPanel(on) {
			var fc_rules = $('#fc_rules');
			if(!fc_rules.length) {
				fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
			}
			fc_rules.text(!on?"":" #tool_topath { display: none !important; }");
			$('#foreignObject_panel').toggle(on);
		}

		function toggleSourceButtons(on) {
			$('#tool_source_save, #tool_source_cancel').toggle(!on);
			$('#foreign_save, #foreign_cancel').toggle(on);
		}

		// Function: setForeignString(xmlString, elt)
		// This function sets the content of element elt to the input XML.
		//
		// Parameters:
		// xmlString - The XML text.
		// elt - the parent element to append to
		//
		// Returns:
		// This function returns false if the set was unsuccessful, true otherwise.
		function setForeignString(xmlString) {
			var elt = selElems[0];
			try {
				// convert string into XML document
				var newDoc = Utils.text2xml('<svg xmlns="'+svgns+'" xmlns:xlink="'+xlinkns+'">'+xmlString+'</svg>');
				// run it through our sanitizer to remove anything we do not support
				S.sanitizeSvg(newDoc.documentElement);
				elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
				S.call("changed", [elt]);
				svgCanvas.clearSelection();
			} catch(e) {
				console.log(e);
				return false;
			}

			return true;
		};

		function showForeignEditor() {
			var elt = selElems[0];
			if (!elt || editingforeign) return;
			editingforeign = true;
			toggleSourceButtons(true);
			elt.removeAttribute('fill');

			var str = S.svgToString(elt, 0);
			$('#svg_source_textarea').val(str);
			$('#svg_source_editor').fadeIn();
			properlySourceSizeTextArea();
			$('#svg_source_textarea').focus();
		}

		function setAttr(attr, val) {
			svgCanvas.changeSelectedAttribute(attr, val);
			S.call("changed", selElems);
		}

		return {
			name: "foreignObject",
			svgicons: "extensions/foreignobject-icons.xml",
			buttons: [{
				id: "tool_foreign",
				type: "mode",
				title: "Foreign Object Tool",
				events: {
					'click': function() {
						svgCanvas.setMode('foreign')
					}
				}
			},{
				id: "edit_foreign",
				type: "context",
				panel: "foreignObject_panel",
				title: "Edit ForeignObject Content",
				events: {
					'click': function() {
						showForeignEditor();
					}
				}
			}],

			context_tools: [{
				type: "input",
				panel: "foreignObject_panel",
				title: "Change foreignObject's width",
				id: "foreign_width",
				label: "w",
				size: 3,
				events: {
					change: function() {
						setAttr('width', this.value);
					}
				}
			},{
				type: "input",
				panel: "foreignObject_panel",
				title: "Change foreignObject's height",
				id: "foreign_height",
				label: "h",
				events: {
					change: function() {
						setAttr('height', this.value);
					}
				}
			}, {
				type: "input",
				panel: "foreignObject_panel",
				title: "Change foreignObject's height",
				id: "foreign_font_size",
				label: "font-size",
				size: 2,
				defval: 16,
				events: {
					change: function() {
						setAttr('font-size', this.value);
					}
				}
			}

			],
			callback: function() {
				$('#foreignObject_panel').hide();

				var endChanges = function() {
					$('#svg_source_editor').hide();
					editingforeign = false;
					$('#svg_source_textarea').blur();
					toggleSourceButtons(false);
				}

				// TODO: Needs to be done after orig icon loads
				setTimeout(function() {
					// Create source save/cancel buttons
					var save = $('#tool_source_save').clone()
						.hide().attr('id', 'foreign_save').unbind()
						.appendTo("#tool_source_back").click(function() {

							if (!editingforeign) return;

							if (!setForeignString($('#svg_source_textarea').val())) {
								$.confirm("Errors found. Revert to original?", function(ok) {
									if(!ok) return false;
									endChanges();
								});
							} else {
								endChanges();
							}
							// setSelectMode();
						});

					var cancel = $('#tool_source_cancel').clone()
						.hide().attr('id', 'foreign_cancel').unbind()
						.appendTo("#tool_source_back").click(function() {
							endChanges();
						});

				}, 3000);
			},
			mouseDown: function(opts) {
				var e = opts.event;

				if(svgCanvas.getMode() == "foreign") {

					started = true;
					newFO = S.addSvgElementFromJson({
						"element": "foreignObject",
						"attr": {
							"x": opts.start_x,
							"y": opts.start_y,
							"id": S.getNextId(),
							"font-size": 16, //cur_text.font_size,
							"width": "48",
							"height": "20",
							"style": "pointer-events:inherit"
						}
					});
					var m = svgdoc.createElementNS(mathns, 'math');
					m.setAttributeNS(xmlnsns, 'xmlns', mathns);
					m.setAttribute('display', 'inline');
					var mi = svgdoc.createElementNS(mathns, 'mi');
					mi.setAttribute('mathvariant', 'normal');
					mi.textContent = "\u03A6";
					var mo = svgdoc.createElementNS(mathns, 'mo');
					mo.textContent = "\u222A";
					var mi2 = svgdoc.createElementNS(mathns, 'mi');
					mi2.textContent = "\u2133";
					m.appendChild(mi);
					m.appendChild(mo);
					m.appendChild(mi2);
					newFO.appendChild(m);
					return {
						started: true
					}
				}
			},
			mouseUp: function(opts) {
				var e = opts.event;
				if(svgCanvas.getMode() == "foreign" && started) {
					var attrs = $(newFO).attr(["width", "height"]);
					keep = (attrs.width != 0 || attrs.height != 0);
					svgCanvas.addToSelection([newFO], true);

					return {
						keep: keep,
						element: newFO
					}

				}

			},
			selectedChanged: function(opts) {
				// Use this to update the current selected elements
				selElems = opts.elems;

				var i = selElems.length;

				while(i--) {
					var elem = selElems[i];
					if(elem && elem.tagName == "foreignObject") {
						if(opts.selectedElement && !opts.multiselected) {
							$('#foreign_font_size').val(elem.getAttribute("font-size"));
							$('#foreign_width').val(elem.getAttribute("width"));
							$('#foreign_height').val(elem.getAttribute("height"));

							showPanel(true);
						} else {
							showPanel(false);
						}
					} else {
						showPanel(false);
					}
				}
			},
			elementChanged: function(opts) {
				var elem = opts.elems[0];
			}
		};
	});
});
<|endoftext|>


<commit_before>const path = require('path');
const program = require('commander');
const packageJson = require('./package.json');
const configStore = require('./utils/config-store');
const { readYamlFileSync } = require('./utils/yaml');
const configSchema = readYamlFileSync(path.join(__dirname, './utils/config.schema.yml'));

// global `bolt` cli options & meta
program
  .version(packageJson.version)
  .option('-C, --config-file <path>', 'Pass in a specific config file instead of default of ".boltrc.js/json".')
  .option('--prod', configSchema.properties.prod.description)
  .option('-v, --verbosity <amount>', configSchema.properties.verbosity.description, parseInt);

// We need to initialize config as early as possible
const configFilePath = path.resolve(process.cwd(), program.configFile || '.boltrc');
const config = configStore.init(require(configFilePath));
// Now that config is initilized, we can start requiring other things

const { buildBoltManifest } = require('./utils/manifest');
const log = require('./utils/log');

/**
 * Update config with all options flags
 * @param {Object} options
 * @param programInstance - The commander `program`
 * @returns {Object} config - Final updated config
 */
async function updateConfig(options, programInstance) {
  configStore.updateConfig((config) => {
    config.verbosity = typeof program.verbosity === 'undefined'
      ? config.verbosity
      : program.verbosity;

    config.openServerAtStart = typeof options.open === 'undefined'
      ? config.openServerAtStart
      : options.open;

    config.webpackStats = typeof options.webpackStats === 'undefined'
      ? config.webpackStats
      : options.webpackStats;

    config.webpackDevServer = typeof options.webpackDevServer === 'undefined'
      ? config.webpackDevServer
      : options.webpackDevServer;

    config.quick = typeof options.quick === 'undefined'
      ? config.quick
      : options.quick;

    config.prod = typeof program.prod === 'undefined'
      ? config.prod
      : program.prod;

    return config;
  });

  const config = configStore.getConfig();
  log.dim(`Verbosity: ${config.verbosity}`);
  log.dim(`Prod: ${config.prod}`);
  if (config.verbosity > 2){
    log.dim(`Opening browser: ${config.openServerAtStart}`);
    log.dim(`Quick mode: ${config.quick}`);
    log.dim(`buildDir: ${config.buildDir}`);
    log.dim(`dataDir: ${config.dataDir}`);
    log.dim(`wwwDir: ${config.wwwDir}`);
  }

  // Basically at this point, the cli is bootstrapped and ready to go.
  // Let's build the core bolt manifest
  await buildBoltManifest();
  return config;
}

log.intro();

// `bolt build`
program
  .command('build')
  .description('Build it')
  .option('--webpack-stats', configSchema.properties.webpackStats.description)
  .option('-Q, --quick', configSchema.properties.quick.description)
  .action(async (options) => {
    log.info(`Starting build (${options.parallel ? 'parallel' : 'serial'})`);
    await updateConfig(options, program);
    require('./tasks/task-collections').build();
  });

program
  .command('serve')
  .description('Spin up local server')
  .option('-O, --open', configSchema.properties.openServerAtStart.description)
  .option('--webpack-dev-server', configSchema.properties.webpackDevServer.description)
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').serve();
  });

program
  .command('watch')
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').watch();
  });

program
  .command('clean')
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').clean();
  });

program
  .command('start')
  .option('-O, --open', configSchema.properties.openServerAtStart.description)
  .option('-Q, --quick', configSchema.properties.quick.description)
  .option('--webpack-dev-server', configSchema.properties.webpackDevServer.description)
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').start();
  });

// `bolt lint`
program
  .command('lint')
  .description('A linter... that doesn\'t work!')
  .action(async (options) => {
    await updateConfig(options, program);
  });

program
  .command('img')
  .description('Image process')
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').images();
  });

program
  .command('webpack')
  .alias('wp')
  .description('WebPack Compile')
  .option('--webpack-stats', configSchema.properties.webpackStats.description)
  .action(async (options) => {
    await updateConfig(options, program);
    try {
      await require('./tasks/webpack-tasks').compile();
    } catch (error) {
      log.errorAndExit('WebPack failed', error);
    }
  });

if (config.env === 'pl'){
  program
    .command('pattern-lab')
    .alias('pl')
    .description('Pattern Lab Compile')
    .action(async (options) => {
      await updateConfig(options, program);
      try {
        await require('./tasks/pattern-lab-tasks').compile();
      } catch (error) {
        log.errorAndExit('Pattern Lab failed', error);
      }
    });
}

// This will tell you all that got `require()`-ed
// We want to only load what we need - that's why not all `require` statements are at top
// log.info('All that got `require()`-ed');
// console.log(Object.keys(require.cache).filter(x => !x.includes('node_modules')));
// log.info('END: All that got `require()`-ed');

// cli init ~ must go at bottom
program.parse(process.argv);
<commit_msg>fix(build-tools/cli.js): Fix for .boltrc.js cli flag override<commit_after>const path = require('path');
const program = require('commander');
const packageJson = require('./package.json');
const configStore = require('./utils/config-store');
const { readYamlFileSync } = require('./utils/yaml');
const configSchema = readYamlFileSync(path.join(__dirname, './utils/config.schema.yml'));

// global `bolt` cli options & meta
program
  .version(packageJson.version)
  .option('-C, --config-file <path>', 'Pass in a specific config file instead of default of ".boltrc.js/json".')
  .option('--prod', configSchema.properties.prod.description)
  .option('-v, --verbosity <amount>', configSchema.properties.verbosity.description, parseInt)
  .parse(process.argv);

// We need to initialize config as early as possible
const configFilePath = path.resolve(process.cwd(), program.configFile || '.boltrc');
const config = configStore.init(require(configFilePath));
// Now that config is initilized, we can start requiring other things

const { buildBoltManifest } = require('./utils/manifest');
const log = require('./utils/log');

/**
 * Update config with all options flags
 * @param {Object} options
 * @param programInstance - The commander `program`
 * @returns {Object} config - Final updated config
 */
async function updateConfig(options, programInstance) {
  configStore.updateConfig((config) => {
    config.verbosity = typeof program.verbosity === 'undefined'
      ? config.verbosity
      : program.verbosity;

    config.openServerAtStart = typeof options.open === 'undefined'
      ? config.openServerAtStart
      : options.open;

    config.webpackStats = typeof options.webpackStats === 'undefined'
      ? config.webpackStats
      : options.webpackStats;

    config.webpackDevServer = typeof options.webpackDevServer === 'undefined'
      ? config.webpackDevServer
      : options.webpackDevServer;

    config.quick = typeof options.quick === 'undefined'
      ? config.quick
      : options.quick;

    config.prod = typeof program.prod === 'undefined'
      ? config.prod
      : program.prod;

    return config;
  });

  const config = configStore.getConfig();
  log.dim(`Verbosity: ${config.verbosity}`);
  log.dim(`Prod: ${config.prod}`);
  if (config.verbosity > 2){
    log.dim(`Opening browser: ${config.openServerAtStart}`);
    log.dim(`Quick mode: ${config.quick}`);
    log.dim(`buildDir: ${config.buildDir}`);
    log.dim(`dataDir: ${config.dataDir}`);
    log.dim(`wwwDir: ${config.wwwDir}`);
  }

  // Basically at this point, the cli is bootstrapped and ready to go.
  // Let's build the core bolt manifest
  await buildBoltManifest();
  return config;
}

log.intro();

// `bolt build`
program
  .command('build')
  .description('Build it')
  .option('--webpack-stats', configSchema.properties.webpackStats.description)
  .option('-Q, --quick', configSchema.properties.quick.description)
  .action(async (options) => {
    log.info(`Starting build (${options.parallel ? 'parallel' : 'serial'})`);
    await updateConfig(options, program);
    require('./tasks/task-collections').build();
  });

program
  .command('serve')
  .description('Spin up local server')
  .option('-O, --open', configSchema.properties.openServerAtStart.description)
  .option('--webpack-dev-server', configSchema.properties.webpackDevServer.description)
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').serve();
  });

program
  .command('watch')
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').watch();
  });

program
  .command('clean')
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').clean();
  });

program
  .command('start')
  .option('-O, --open', configSchema.properties.openServerAtStart.description)
  .option('-Q, --quick', configSchema.properties.quick.description)
  .option('--webpack-dev-server', configSchema.properties.webpackDevServer.description)
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').start();
  });

// `bolt lint`
program
  .command('lint')
  .description('A linter... that doesn\'t work!')
  .action(async (options) => {
    await updateConfig(options, program);
  });

program
  .command('img')
  .description('Image process')
  .action(async (options) => {
    await updateConfig(options, program);
    require('./tasks/task-collections').images();
  });

program
  .command('webpack')
  .alias('wp')
  .description('WebPack Compile')
  .option('--webpack-stats', configSchema.properties.webpackStats.description)
  .action(async (options) => {
    await updateConfig(options, program);
    try {
      await require('./tasks/webpack-tasks').compile();
    } catch (error) {
      log.errorAndExit('WebPack failed', error);
    }
  });

if (config.env === 'pl'){
  program
    .command('pattern-lab')
    .alias('pl')
    .description('Pattern Lab Compile')
    .action(async (options) => {
      await updateConfig(options, program);
      try {
        await require('./tasks/pattern-lab-tasks').compile();
      } catch (error) {
        log.errorAndExit('Pattern Lab failed', error);
      }
    });
}

// This will tell you all that got `require()`-ed
// We want to only load what we need - that's why not all `require` statements are at top
// log.info('All that got `require()`-ed');
// console.log(Object.keys(require.cache).filter(x => !x.includes('node_modules')));
// log.info('END: All that got `require()`-ed');

// cli init ~ must go at bottom
program.parse(process.argv);
<|endoftext|>


<commit_before>var Q = require('q');
var resultFixtures = require('../support/searchResult48');
var jasminePit = require('jasmine-pit');
var _ = require('lodash');

var setExpectedResultAndGetSearchPromise = require('../support/testSwaggerClientPromiseFactory')('geneSearch', resultFixtures);

jasminePit.install(global);
require('jasmine-expect');

describe('geneSearch', function () {

  var searchInterface = require('../../src/searchInterface')
  var grameneSwaggerClient = require('../../src/grameneSwaggerClient');

  //var expectedResult;
  //
  //function setExpectedResultAndGetSearchPromise(name) {
  //  var fixture = resultFixtures[name];
  //  expectedResult = fixture.response.obj;
  //
  //  // comment out this line to test with real server
  //  spyOn(grameneSwaggerClient, 'then').andReturn(Q(_.cloneDeep(fixture.response)));
  //
  //  return searchInterface.geneSearch(fixture.query);
  //}

  function checkResultCounts(searchResult, expectedResult) {
    expect(searchResult).toBeDefined();
    expect(searchResult.metadata).toBeDefined();
    expect(searchResult.metadata.count).toEqual(expectedResult.response.numFound);
  }

  // not currently using / supporting this functionality.
  xit('should process tally correctly', function () {
    var searchPromise = setExpectedResultAndGetSearchPromise('tally');

    return searchPromise.then(function (searchResult) {
      checkResultCounts(searchResult, searchPromise.unprocessedResponse);

      expect(searchResult.tally).toBeDefined();
      expect(searchResult.tally.GO).toEqual(searchPromise.unprocessedResponse.facets.GO);
      expect(searchResult.tally.PO).toEqual(searchPromise.unprocessedResponse.facets.PO);
      expect(searchResult.tally.species).toEqual(searchPromise.unprocessedResponse.facets.species);
      expect(searchResult.tally.domains).toEqual(searchPromise.unprocessedResponse.facets.domains);
      expect(searchResult.tally.biotype).toEqual(searchPromise.unprocessedResponse.facets.biotype);

    });
  });

  pit('should process facet correctly', function () {
    var searchPromise = setExpectedResultAndGetSearchPromise('faceted');

    return searchPromise.then(function (searchResult) {
      checkResultCounts(searchResult, searchPromise.unprocessedResponse);

      // this is an object of results
      var taxonFacetResults = searchResult.taxon_id;
      expect(taxonFacetResults).toBeDefined();

      // this is an array of alternating keys and values as returned from SOLR
      var unprocessedTaxonIdsFromFixture = _.chunk(searchPromise.unprocessedResponse.facet_counts.facet_fields.taxon_id, 2);
      var countTaxonIdsWithAtLeastOneResult = _.filter(unprocessedTaxonIdsFromFixture, function(i) {
        return i[1] > 0;
      }).length;

      expect(_.size(taxonFacetResults.data)).toEqual(_.size(taxonFacetResults.sorted));
      expect(_.size(taxonFacetResults.data)).toEqual(_.size(unprocessedTaxonIdsFromFixture));
      expect(taxonFacetResults.count).toEqual(countTaxonIdsWithAtLeastOneResult);

      for(var i = 0; i < taxonFacetResults.sorted.length; i++) {
        var taxonFacet = taxonFacetResults.sorted[i];

        expect(taxonFacet.id).toEqual(+unprocessedTaxonIdsFromFixture[i][0]);
        expect(taxonFacet.count).toEqual(unprocessedTaxonIdsFromFixture[i][1]);
      }
    });
  });

  pit('should get result list', function () {
    var searchPromise = setExpectedResultAndGetSearchPromise('rows10');

    return searchPromise.then(function (searchResult) {
      checkResultCounts(searchResult, searchPromise.unprocessedResponse);

      expect(searchResult.list.length).toEqual(5);

      _.forEach(searchResult.list, function (doc, idx) {
        var expectedDoc = searchPromise.unprocessedResponse.response.docs[idx];
        expect(doc.id).toEqual(expectedDoc.id);
      })
    });
  });

  it('should allow test searches to be performed', function () {
    return searchInterface._testSearch('binned').then(function (data) {
      expect(data).toBeDefined();
    })
  });

});<commit_msg>remove old code<commit_after>var Q = require('q');
var resultFixtures = require('../support/searchResult48');
var jasminePit = require('jasmine-pit');
var _ = require('lodash');

var setExpectedResultAndGetSearchPromise = require('../support/testSwaggerClientPromiseFactory')('geneSearch', resultFixtures);

jasminePit.install(global);
require('jasmine-expect');

describe('geneSearch', function () {

  var searchInterface = require('../../src/searchInterface');
  var grameneSwaggerClient = require('../../src/grameneSwaggerClient');

  function checkResultCounts(searchResult, expectedResult) {
    expect(searchResult).toBeDefined();
    expect(searchResult.metadata).toBeDefined();
    expect(searchResult.metadata.count).toEqual(expectedResult.response.numFound);
  }

  pit('should process facet correctly', function () {
    var searchPromise = setExpectedResultAndGetSearchPromise('faceted');

    return searchPromise.then(function (searchResult) {
      checkResultCounts(searchResult, searchPromise.unprocessedResponse);

      // this is an object of results
      var taxonFacetResults = searchResult.taxon_id;
      expect(taxonFacetResults).toBeDefined();

      // this is an array of alternating keys and values as returned from SOLR
      var unprocessedTaxonIdsFromFixture = _.chunk(searchPromise.unprocessedResponse.facet_counts.facet_fields.taxon_id, 2);
      var countTaxonIdsWithAtLeastOneResult = _.filter(unprocessedTaxonIdsFromFixture, function(i) {
        return i[1] > 0;
      }).length;

      expect(_.size(taxonFacetResults.data)).toEqual(_.size(taxonFacetResults.sorted));
      expect(_.size(taxonFacetResults.data)).toEqual(_.size(unprocessedTaxonIdsFromFixture));
      expect(taxonFacetResults.count).toEqual(countTaxonIdsWithAtLeastOneResult);

      for(var i = 0; i < taxonFacetResults.sorted.length; i++) {
        var taxonFacet = taxonFacetResults.sorted[i];

        expect(taxonFacet.id).toEqual(+unprocessedTaxonIdsFromFixture[i][0]);
        expect(taxonFacet.count).toEqual(unprocessedTaxonIdsFromFixture[i][1]);
      }
    });
  });

  pit('should get result list', function () {
    var searchPromise = setExpectedResultAndGetSearchPromise('rows10');

    return searchPromise.then(function (searchResult) {
      checkResultCounts(searchResult, searchPromise.unprocessedResponse);

      expect(searchResult.list.length).toEqual(5);

      _.forEach(searchResult.list, function (doc, idx) {
        var expectedDoc = searchPromise.unprocessedResponse.response.docs[idx];
        expect(doc.id).toEqual(expectedDoc.id);
      })
    });
  });

  it('should allow test searches to be performed', function () {
    return searchInterface._testSearch('binned').then(function (data) {
      expect(data).toBeDefined();
    })
  });

});<|endoftext|>


<commit_before>'use strict';

var staticx = require('../../lib/staticx.js');
var fs = require('fs-extra');
var async = require('async');

describe('Scaffolding', function() {

  it('Should remove a directory', function(done){
    fs.mkdir('spec/fixtures/tmp/remove',function(err) {
      if (err) return done(err);
      staticx.scaffold.remove('spec/fixtures/tmp/remove', function(err) {
        if (err) return done(err);
        fs.exists('spec/fixtures/tmp/remove', function (exists) {
          done(!exists ? null : 'Directory still exists');
        });
      });
    });
  });

  it('Should clean a directory', function(done){
    fs.mkdir('spec/fixtures/tmp/tmpclean', function(err) {
      if (err) return done(err);
      fs.writeFile('spec/fixtures/tmp/tmpclean/file', 'Hello', function(err) {
        if (err) return done(err);
        expect(fs.existsSync('spec/fixtures/tmp/tmpclean/file')).toBe(true);
        staticx.scaffold.clean('spec/fixtures/tmp/tmpclean', function() {
          expect(fs.existsSync('spec/fixtures/tmp/tmpclean')).toBe(true);
          expect(fs.existsSync('spec/fixtures/tmp/tmpclean/file')).toBe(false);
          fs.remove('spec/fixtures/tmp/tmpclean', done);
        });
      });
    });
  });

  it('Should copy the skeleton files to a new directory', function(done){

    var scaffold = staticx.scaffold;
    var source = 'lib/skeleton';
    var dest = 'spec/fixtures/tmp/skeleton';

    fs.mkdir(dest, function(err) {
      if (err) return done(err);
      scaffold.copy(source, dest, function(err) {
        if (err) return done(err);
        fs.exists(dest, function (exists) {
          if (!exists) return done('The destination folder does not exists: ' + dest);
          scaffold.clean(dest, function(err) {
            if (err) return done(err);
            fs.remove(dest, done);
          });
        });
      });
    });
  });

  var createdPosts = [];

  it('Should create posts in markdown format', function(done) {

    var scaffold = staticx.scaffold;

    function checkPostExists(page) {
      return function(next) {
        fs.exists(page.filePath, function(exists) {
          if (!exists) return next('Page does not exist on filesystem: ' + page.filePath);
          fs.readFile(page.filePath, function(err, data) {
            if (err) return done(err);
            if (!data.toString().trim()) {
              next('No data in file create scaffold page file.');
            } else {
              next(null);
            }
          });
        });
      };
    }

    function onCreatePosts(err, posts) {
      if (err) return done(err);
      // Expose the created posts so we can use them in other tests.
      createdPosts = posts;
      // Here we check there's actually some content in the generated files...
      async.series(posts.map(checkPostExists), done);
    }

    scaffold.createPosts({
      destination: 'spec/fixtures/tmp',
      posts: 7
    }, onCreatePosts);
  });

  it('Should remove an array of created pages', function(done) {
    staticx.scaffold.removePages(createdPosts, function(err) {
      if (err) return done(err);
      async.forEach(createdPosts, function(post, callback) {
        fs.exists(post.filePath, function(exists) {
          if (exists) return done('Created page still exist on the filesystem: ' + post.filePath);
          callback();
        });
      }, done);
    });
  });

  it('Should create a new skeleton site with optional blog posts', function(done) {

    var options = {
      destination: 'spec/fixtures/tmp/create',
      posts: '10',
      clean: 'y'
    };

    fs.mkdir(options.destination, function(err) {
      if (err) return done(err);
      staticx.create(options, function(err) {
        if (err) return done(err);
        fs.remove(options.destination, done);
      });
    });
  });
});
<commit_msg>Added test for creating a new site<commit_after>/*
 * staticx
 * https://github.com/badsyntax/staticx
 *
 * Copyright (c) 2013 Richard Willis
 * Licensed under the MIT license.
 */
'use strict';

var staticx = require('../../lib/staticx');
var fs = require('fs-extra');
var async = require('async');
var _ = require('lodash');

describe('Scaffolding', function() {

  it('Should remove a directory', function(done){
    fs.mkdir('spec/fixtures/tmp/remove',function(err) {
      if (err) return done(err);
      staticx.scaffold.remove('spec/fixtures/tmp/remove', function(err) {
        if (err) return done(err);
        fs.exists('spec/fixtures/tmp/remove', function (exists) {
          done(!exists ? null : 'Directory still exists');
        });
      });
    });
  });

  it('Should clean a directory', function(done){
    fs.mkdir('spec/fixtures/tmp/tmpclean', function(err) {
      if (err) return done(err);
      fs.writeFile('spec/fixtures/tmp/tmpclean/file', 'Hello', function(err) {
        if (err) return done(err);
        expect(fs.existsSync('spec/fixtures/tmp/tmpclean/file')).toBe(true);
        staticx.scaffold.clean('spec/fixtures/tmp/tmpclean', function() {
          expect(fs.existsSync('spec/fixtures/tmp/tmpclean')).toBe(true);
          expect(fs.existsSync('spec/fixtures/tmp/tmpclean/file')).toBe(false);
          fs.remove('spec/fixtures/tmp/tmpclean', done);
        });
      });
    });
  });

  it('Should copy the skeleton files to a new directory', function(done){

    var scaffold = staticx.scaffold;
    var source = 'lib/skeleton';
    var dest = 'spec/fixtures/tmp/skeleton';

    fs.mkdir(dest, function(err) {
      if (err) return done(err);
      scaffold.copy(source, dest, function(err) {
        if (err) return done(err);
        fs.exists(dest, function (exists) {
          if (!exists) return done('The destination folder does not exists: ' + dest);
          scaffold.clean(dest, function(err) {
            if (err) return done(err);
            fs.remove(dest, done);
          });
        });
      });
    });
  });

  var createdPosts = [];

  it('Should create posts in markdown format', function(done) {

    var scaffold = staticx.scaffold;

    function checkPostExists(page) {
      return function(next) {
        fs.exists(page.filePath, function(exists) {
          if (!exists) return next('Page does not exist on filesystem: ' + page.filePath);
          fs.readFile(page.filePath, function(err, data) {
            if (err) return done(err);
            if (!data.toString().trim()) {
              next('No data in file create scaffold page file.');
            } else {
              next(null);
            }
          });
        });
      };
    }

    function onCreatePosts(err, posts) {
      if (err) return done(err);
      // Expose the created posts so we can use them in other tests.
      createdPosts = posts;
      // Here we check there's actually some content in the generated files...
      async.parallel(posts.map(checkPostExists), done);
    }

    scaffold.createPosts({
      destination: 'spec/fixtures/tmp',
      posts: 7
    }, onCreatePosts);
  });

  it('Should remove an array of created pages', function(done) {
    staticx.scaffold.removePages(createdPosts, function(err) {
      if (err) return done(err);
      async.forEach(createdPosts, function(post, callback) {
        fs.exists(post.filePath, function(exists) {
          if (exists) return done('Created page still exist on the filesystem: ' + post.filePath);
          callback();
        });
      }, done);
    });
  });

  it('Should create a new skeleton site with optional blog posts', function(done) {

    var options = {
      destination: 'spec/fixtures/tmp/create',
      posts: '10',
      clean: 'y'
    };

    spyOn(staticx.scaffold, 'copy').andCallThrough();
    spyOn(staticx.scaffold, 'createPosts').andCallThrough();
    spyOn(staticx.scaffold, 'clean').andCallThrough();

    fs.mkdir(options.destination, function(err) {
      if (err) return done(err);
      staticx.create(options, function(err) {
        if (err) return done(err);
        // Check that scaffold.copy was called.
        expect(staticx.scaffold.copy).toHaveBeenCalled();
        expect(staticx.scaffold.copy.mostRecentCall.args[0]).toEqual('lib/skeleton');
        expect(staticx.scaffold.copy.mostRecentCall.args[1]).toEqual(options.destination);
        // Check that scaffold.createPosts was called.
        expect(staticx.scaffold.createPosts).toHaveBeenCalled();
        expect(staticx.scaffold.createPosts.mostRecentCall.args[0]).toEqual(
          _.extend({}, options, {
            destination: 'spec/fixtures/tmp/create/_pages/blog',
            source : 'lib/skeleton'
          })
        );
        // Check that scaffold.clean was called.
        expect(staticx.scaffold.clean).toHaveBeenCalled();
        // Remove tmp dir.
        fs.remove(options.destination, done);
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var add = require('../src/stringCalculator');
var chai = require('chai');

chai.should();

describe('String calculator', function () {
  describe('Add function', function () {
    it('should return 0 when empty string is provided', function () {
      var result = add('');

      result.should.be.a('number');
      result.should.be.equal(0);
    });

    it('should return 1 when "1" is provided', function () {
      add('1').should.be.equal(1);
    });

    it('should return the sum of both numbers', function () {
      add('1,2').should.be.equal(3);
    });

    it('should return the sum of all numbers', function () {
      add('1,3,5,6,2').should.be.equal(17);
    });

    it('should not add numbers greater than 1000', function () {
      add('1000, 3, 1002').should.be.equal(1003);
    });
  });

  describe('Delimiters', function () {
    it('should accept new lines as separators', function () {
      add('7,3\n4').should.be.equal(14);
    });

    it('should accept custom separators', function () {
      add('//;\n1;3;5').should.be.equal(9);
    });

    it('should accept custom separators along with default ones', function () {
      add('//_\n6,7\n1_2').should.be.equal(16);
    });

    it('should accept multi-char custom delimiter', function () {
      add('//[***]\n1***2***7').should.be.equal(10);
    });
  });

  describe('Negative number error', function () {
    it('should throw a RangeError when a negative number is found', function () {
      var evaluator = function () {
        add('4,-3,5');
      };

      evaluator.should.throw(RangeError);
    });

    it('should throw an error including a negative value', function () {
      var evaluator = function () {
        add('4,-3,5');
      };

      evaluator.should.throw(RangeError, /^Negatives not allowed: -\d$/);
    });

    it('should throw an error including list of negative values', function () {
      var evaluator = function () {
        add('4,-3,-5, 6, -10');
      };

      evaluator.should.throw(RangeError, /^Negatives not allowed: (?:-\d+,)*-\d+$/);
    });
  });
});<commit_msg>Better wording on delimiter specs<commit_after>'use strict';

var add = require('../src/stringCalculator');
var chai = require('chai');

chai.should();

describe('String calculator', function () {
  describe('Add function', function () {
    it('should return 0 when empty string is provided', function () {
      var result = add('');

      result.should.be.a('number');
      result.should.be.equal(0);
    });

    it('should return 1 when "1" is provided', function () {
      add('1').should.be.equal(1);
    });

    it('should return the sum of both numbers', function () {
      add('1,2').should.be.equal(3);
    });

    it('should return the sum of all numbers', function () {
      add('1,3,5,6,2').should.be.equal(17);
    });

    it('should not add numbers greater than 1000', function () {
      add('1000, 3, 1002').should.be.equal(1003);
    });
  });

  describe('Delimiters', function () {
    it('should accept new lines as delimiter', function () {
      add('7,3\n4').should.be.equal(14);
    });

    it('should accept custom delimiter', function () {
      add('//;\n1;3;5').should.be.equal(9);
    });

    it('should accept custom delimiter along with default ones', function () {
      add('//_\n6,7\n1_2').should.be.equal(16);
    });

    it('should accept multi-char custom delimiter', function () {
      add('//[***]\n1***2***7').should.be.equal(10);
    });
  });

  describe('Negative number error', function () {
    it('should throw a RangeError when a negative number is found', function () {
      var evaluator = function () {
        add('4,-3,5');
      };

      evaluator.should.throw(RangeError);
    });

    it('should throw an error including a negative value', function () {
      var evaluator = function () {
        add('4,-3,5');
      };

      evaluator.should.throw(RangeError, /^Negatives not allowed: -\d$/);
    });

    it('should throw an error including list of negative values', function () {
      var evaluator = function () {
        add('4,-3,-5, 6, -10');
      };

      evaluator.should.throw(RangeError, /^Negatives not allowed: (?:-\d+,)*-\d+$/);
    });
  });
});<|endoftext|>


<commit_before>/**
 * AdSense AdBlockerWarning component.
 *
 * Site Kit by Google, Copyright 2020 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { SvgIcon } from '../../../util';
import { STORE_NAME } from '../datastore';
const { useSelect } = Data;

export default function AdBlockerWarning() {
	const isAdBlockerActive = useSelect( ( select ) => select( STORE_NAME ).isAdBlockerActive() );

	// Return nothing if loading or if everything is fine.
	if ( ! isAdBlockerActive ) {
		return null;
	}

	return (
		<div className="googlesitekit-settings-module-warning">
			<SvgIcon id="error" height="20" width="23" /> { __( 'Ad blocker detected, you need to disable it in order to setup AdSense.', 'google-site-kit' ) }
		</div>
	);
}
<commit_msg>Make AdBlockerWarning component more flexible to account for use in different contexts.<commit_after>/**
 * AdSense AdBlockerWarning component.
 *
 * Site Kit by Google, Copyright 2020 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { SvgIcon } from '../../../util';
import { STORE_NAME } from '../datastore';
const { useSelect } = Data;

export default function AdBlockerWarning( { context } ) {
	const isAdBlockerActive = useSelect( ( select ) => select( STORE_NAME ).isAdBlockerActive() );
	const isAccountSetupComplete = useSelect( ( select ) => select( STORE_NAME ).getAccountSetupComplete() );
	const isSiteSetupComplete = useSelect( ( select ) => select( STORE_NAME ).getSiteSetupComplete() );

	// Return nothing if loading or if everything is fine.
	if ( ! isAdBlockerActive ) {
		return null;
	}

	let message;
	if ( isAccountSetupComplete && isSiteSetupComplete ) {
		message = __( 'Ad blocker detected, you need to disable it to get the AdSense latest data.', 'google-site-kit' );
	} else {
		message = __( 'Ad blocker detected, you need to disable it in order to setup AdSense.', 'google-site-kit' );
	}

	return (
		<div
			className={ classnames(
				'googlesitekit-settings-module-warning',
				{ [ `googlesitekit-settings-module-warning--${ context }` ]: context }
			) }
		>
			<SvgIcon id="error" height="20" width="23" /> { message }
		</div>
	);
}

AdBlockerWarning.propTypes = {
	context: PropTypes.string,
};

AdBlockerWarning.defaultProps = {
	context: '',
};
<|endoftext|>


<commit_before>/**
 * External dependencies
 */
import classnames from 'classnames';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import {
	Dashicon,
	IconButton,
} from '@wordpress/components';
import {
	URLInput,
	RichText,
} from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import './edit.css';
import { select } from '@wordpress/data';
import { getUniqueId } from '../../helpers';
import { getBackgroundColorWithOpacity } from '../../../common/helpers';

class CallToActionEdit extends Component {
	constructor( props ) {
		super( props );

		if ( ! props.attributes.anchor ) {
			this.props.setAttributes( { anchor: getUniqueId() } );
		}

		this.nodeRef = null;
		this.bindRef = this.bindRef.bind( this );
	}

	bindRef( node ) {
		if ( ! node ) {
			return;
		}
		this.nodeRef = node;
	}

	render() {
		const {
			attributes,
			backgroundColor,
			textColor,
			setAttributes,
			isSelected,
			className,
			fontSize,
		} = this.props;

		const {
			text,
			url,
			customBackgroundColor,
			opacity,
		} = attributes;

		const { colors } = select( 'core/block-editor' ).getSettings();
		const appliedBackgroundColor = getBackgroundColorWithOpacity( colors, backgroundColor, customBackgroundColor, opacity );

		return (
			<>

					<RichText
						placeholder={ __( 'Add text…', 'amp' ) }
						value={ text }
						onChange={ ( value ) => setAttributes( { text: value } ) }
						formattingControls={ [ 'bold', 'italic', 'strikethrough' ] }
						className={ classnames(
							'amp-block-story-cta__link', {
								'has-background': backgroundColor.color,
								[ backgroundColor.class ]: backgroundColor.class,
								'has-text-color': textColor.color,
								[ textColor.class ]: textColor.class,
							}
						) }
						style={ {
							backgroundColor: appliedBackgroundColor,
							color: textColor.color,
							fontSize: fontSize.size ? fontSize.size + 'px' : undefined,
						} }
					/>

				{ isSelected && (
					<form
						className="amp-block-story-cta__inline-link"
						onSubmit={ ( event ) => event.preventDefault() }>
						<Dashicon icon="admin-links" />
						<URLInput
							value={ url }
							onChange={ ( value ) => setAttributes( { url: value } ) }
							autoFocus={ false /* eslint-disable-line jsx-a11y/no-autofocus */ }
						/>
						<IconButton icon="editor-break" label={ __( 'Apply', 'amp' ) } type="submit" />
					</form>
				) }
			</>
		);
	}
}

CallToActionEdit.propTypes = {
	attributes: PropTypes.shape( {
		text: PropTypes.string,
		url: PropTypes.string,
		anchor: PropTypes.string,
		customBackgroundColor: PropTypes.string,
		opacity: PropTypes.number,
	} ).isRequired,
	setAttributes: PropTypes.func.isRequired,
	isSelected: PropTypes.bool,
	className: PropTypes.string,
	fontSize: PropTypes.shape( {
		name: PropTypes.string,
		shortName: PropTypes.string,
		size: PropTypes.number,
		slug: PropTypes.string,
	} ).isRequired,
	backgroundColor: PropTypes.shape( {
		color: PropTypes.string,
		name: PropTypes.string,
		slug: PropTypes.string,
		class: PropTypes.string,
	} ).isRequired,
	textColor: PropTypes.shape( {
		color: PropTypes.string,
		name: PropTypes.string,
		slug: PropTypes.string,
		class: PropTypes.string,
	} ).isRequired,
};

export default CallToActionEdit;
<commit_msg>Remove deprecated formattingControls.<commit_after>/**
 * External dependencies
 */
import classnames from 'classnames';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import {
	Dashicon,
	IconButton,
} from '@wordpress/components';
import {
	URLInput,
	RichText,
} from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import './edit.css';
import { select } from '@wordpress/data';
import { getUniqueId } from '../../helpers';
import { getBackgroundColorWithOpacity } from '../../../common/helpers';

class CallToActionEdit extends Component {
	constructor( props ) {
		super( props );

		if ( ! props.attributes.anchor ) {
			this.props.setAttributes( { anchor: getUniqueId() } );
		}

		this.nodeRef = null;
		this.bindRef = this.bindRef.bind( this );
	}

	bindRef( node ) {
		if ( ! node ) {
			return;
		}
		this.nodeRef = node;
	}

	render() {
		const {
			attributes,
			backgroundColor,
			textColor,
			setAttributes,
			isSelected,
			className,
			fontSize,
		} = this.props;

		const {
			text,
			url,
			customBackgroundColor,
			opacity,
		} = attributes;

		const { colors } = select( 'core/block-editor' ).getSettings();
		const appliedBackgroundColor = getBackgroundColorWithOpacity( colors, backgroundColor, customBackgroundColor, opacity );

		return (
			<>

					<RichText
						placeholder={ __( 'Add text…', 'amp' ) }
						value={ text }
						onChange={ ( value ) => setAttributes( { text: value } ) }
						allowedFormats={ [ 'bold', 'italic', 'strikethrough' ] }
						className={ classnames(
							'amp-block-story-cta__link', {
								'has-background': backgroundColor.color,
								[ backgroundColor.class ]: backgroundColor.class,
								'has-text-color': textColor.color,
								[ textColor.class ]: textColor.class,
							}
						) }
						style={ {
							backgroundColor: appliedBackgroundColor,
							color: textColor.color,
							fontSize: fontSize.size ? fontSize.size + 'px' : undefined,
						} }
					/>

				{ isSelected && (
					<form
						className="amp-block-story-cta__inline-link"
						onSubmit={ ( event ) => event.preventDefault() }>
						<Dashicon icon="admin-links" />
						<URLInput
							value={ url }
							onChange={ ( value ) => setAttributes( { url: value } ) }
							autoFocus={ false /* eslint-disable-line jsx-a11y/no-autofocus */ }
						/>
						<IconButton icon="editor-break" label={ __( 'Apply', 'amp' ) } type="submit" />
					</form>
				) }
			</>
		);
	}
}

CallToActionEdit.propTypes = {
	attributes: PropTypes.shape( {
		text: PropTypes.string,
		url: PropTypes.string,
		anchor: PropTypes.string,
		customBackgroundColor: PropTypes.string,
		opacity: PropTypes.number,
	} ).isRequired,
	setAttributes: PropTypes.func.isRequired,
	isSelected: PropTypes.bool,
	className: PropTypes.string,
	fontSize: PropTypes.shape( {
		name: PropTypes.string,
		shortName: PropTypes.string,
		size: PropTypes.number,
		slug: PropTypes.string,
	} ).isRequired,
	backgroundColor: PropTypes.shape( {
		color: PropTypes.string,
		name: PropTypes.string,
		slug: PropTypes.string,
		class: PropTypes.string,
	} ).isRequired,
	textColor: PropTypes.shape( {
		color: PropTypes.string,
		name: PropTypes.string,
		slug: PropTypes.string,
		class: PropTypes.string,
	} ).isRequired,
};

export default CallToActionEdit;
<|endoftext|>


<commit_before>/**
 * Created by Sahib Pandori on 3/28/2017.
 */

/**
 * Contains a list of words used in the speech commands
 */
var allowedWords = [
    'block',
    'connect',
    'get',
    'delete',
    'move',
    'under',
    'right',
    'left',
    'pen',
    'turn',
    'change',
    'to',
    'up',
    'down',
    'run',
    'the',
    'program',
    'a',
    'repeat',
    'in',
    'inside'
];

/**
 * Contains common mistakes made by the speech recognizer and their actual (probably) values
 */
var corrections = {

    'pattern': 'get a turn',
    'kinect': 'connect',
    '2': 'to',
    'white': 'right',
    'write': 'right',
    'up and': 'a pen',
    'for': '4',
    'foreign': '4',
    'ford': '4',
    'war': '4',
    'lakhs': 'block',
    'a pin': 'up in',
    'hey': 'hey jerry',
    'greta': 'get a',
    'text': 'connect',
    'k\'nex': 'connect',
    'blog': 'block',
    'xbox': 'connect block',
    'jetta': 'get a',
    'return': 'get a turn',
    'today': 'get',
    'can you': 'get a',
    'sex': '6',
    'free': '3',
    'tube': '2',
    'walkthrough': 'block 3',
    'force': '4',
    'netflix': 'connect block',
    '100': '1 under',
    '200': '2 under',
    '300': '3 under',
    '400': '4 under',
    '500': '5 under',
    '600': '6 under',
    '700': '7 under',
    '800': '8 under',
    '900': '9 under',
    '1:20': '120',
    '1:44': '144',
    'black tooth': 'block 2',
    'clock': 'block',
    'on': 'block',
    'tattoo pattern': 'get a turn',
    'lot': 'block',
    'blockhead': 'block 8',
    'laugh': 'left',
    'price': '5',
    'glock': 'block',
    'got': 'get',
    'death': 'get',
    'ken': 'pen',
    'tutuapp': 'to up',
    'moon': 'move',
    'ghetto': 'get a',
    'keratin': 'get a turn',
    'garrett on': 'get a turn',
    'torn': 'turn',
    'elite': 'delete',
    'better': 'get a',
    'guitar': 'get a',
    'tone': 'turn',
    'corn': 'turn',
    'the next': 'connect',
    'it': '8'
};

/**
 * Return all possible corrections using only the allowed words (and numbers)
 * @param speech The speech command that isn't recognized
 */
function correct(speech) {

    var possibleCommands = [];
    var words = speech.split(" ");
    // Stores the corrected command
    var command = '';
    // Stores whether all given words in the command are valid
    var invalid = false;

    // Convert each invalid word to a allowed word without searching for wrong pairs of words
    for (var i = 0; i < words.length; i++) {
        // Check for individual invalid words if pairs aren't found
        if (!allowedWords.includes(words[i])) {
            if (words[i] in corrections) {
                command += corrections[words[i]] + ' ';
            } else {
                if (!isNaN(words[i])) {
                    command += words[i] + ' ';
                    continue;
                }
                invalid = true;
                break;
            }
        }
        // Add the word to the command as it's an allowed word
        else {
            command += words[i] + ' ';
        }
    }

    // If all words in the command were valid, then add it as a possible corrected command
    if (!invalid) {
        possibleCommands.push(command.trim());
    }

    invalid = false;
    command = '';

    // Search for any pairs of invalid words and replace them with valid ones (if not search for invalid individual words)
    for (i = 0; i < words.length - 1; i++) {
        // Check for a pair of invalid words
        if (!allowedWords.includes(words[i]) && !allowedWords.includes(words[i+1])) {
            if ((words[i] + ' ' + words[i+1]) in corrections) {
                command += words[i] + ' ' + words[i+1] + ' ';
            }
        }
        // Check for individual invalid words if pairs aren't found
        else if (!allowedWords.includes(words[i])) {
            if (words[i] in corrections) {
                command += corrections[words[i]] + ' ';
            } else {
                if (!isNaN(words[i])) {
                    command += words[i] + ' ';
                    continue;
                }
                invalid = true;
                break;
            }
        }
        // Add the word to the command as it's an allowed word
        else {
            command += words[i] + ' ';
        }
    }

    // If all words in the command are valid and it's not the same as the previous value (if there is one), then add
    // it as a possible corrected command
    if (!invalid) {
        if ((possibleCommands.length > 0 && command != possibleCommands[0]) || possibleCommands.length == 0) {
            possibleCommands.push(command.trim());
        }
    }

    return possibleCommands;
}<commit_msg>fixed some errors in corrections and added more<commit_after>/**
 * Created by Sahib Pandori on 3/28/2017.
 */

/**
 * Contains a list of words used in the speech commands
 */
var allowedWords = [
    'block',
    'connect',
    'get',
    'delete',
    'move',
    'under',
    'right',
    'left',
    'pen',
    'turn',
    'change',
    'to',
    'up',
    'down',
    'run',
    'the',
    'program',
    'a',
    'repeat',
    'in',
    'inside'
];

/**
 * Contains common mistakes made by the speech recognizer and their actual (probably) values
 */
var corrections = {

    'pattern': 'get a turn',
    'kinect': 'connect',
    'to': '2',
    'white': 'right',
    'write': 'right',
    'up and': 'a pen',
    'for': '4',
    'foreign': '4',
    'ford': '4',
    'war': '4',
    'lakhs': 'block',
    'a pin': 'up in',
    'hey': 'hey jerry',
    'greta': 'get a',
    'text': 'connect',
    'k\'nex': 'connect',
    'blog': 'block',
    'xbox': 'connect block',
    'jetta': 'get a',
    'return': 'get a turn',
    'today': 'get',
    'can you': 'get a',
    'sex': '6',
    'free': '3',
    'tube': '2',
    'walkthrough': 'block 3',
    'force': '4',
    'netflix': 'connect block',
    '100': '1 under',
    '200': '2 under',
    '300': '3 under',
    '400': '4 under',
    '500': '5 under',
    '600': '6 under',
    '700': '7 under',
    '800': '8 under',
    '900': '9 under',
    '1:20': '120',
    '1:44': '144',
    'black tooth': 'block 2',
    'clock': 'block',
    'on': 'block',
    'tattoo pattern': 'get a turn',
    'lot': 'block',
    'blockhead': 'block 8',
    'laugh': 'left',
    'price': '5',
    'glock': 'block',
    'got': 'get',
    'death': 'get',
    'ken': 'pen',
    'tutuapp': 'to up',
    'moon': 'move',
    'ghetto': 'get a',
    'keratin': 'get a turn',
    'garrett on': 'get a turn',
    'torn': 'turn',
    'elite': 'delete',
    'better': 'get a',
    'guitar': 'get a',
    'tone': 'turn',
    'corn': 'turn',
    'the next': 'connect',
    'it': '8',
    'phone': 'turn',
    'connector': 'connect'
};

/**
 * Return all possible corrections using only the allowed words (and numbers)
 * @param speech The speech command that isn't recognized
 */
function correct(speech) {

    var possibleCommands = [];
    var words = speech.split(" ");
    // Stores the corrected command
    var command = '';
    // Stores whether all given words in the command are valid
    var invalid = false;

    // Convert each invalid word to a allowed word without searching for wrong pairs of words
    for (var i = 0; i < words.length; i++) {
        // Check for individual invalid words if pairs aren't found
        if (!allowedWords.includes(words[i])) {
            if (words[i] in corrections) {
                command += corrections[words[i]] + ' ';
            } else {
                if (!isNaN(words[i])) {
                    command += words[i] + ' ';
                    continue;
                }
                invalid = true;
                break;
            }
        }
        // Add the word to the command as it's an allowed word
        else {
            command += words[i] + ' ';
        }
    }

    // If all words in the command were valid, then add it as a possible corrected command
    if (!invalid) {
        possibleCommands.push(command.trim());
    }

    invalid = false;
    command = '';

    // Search for any pairs of invalid words and replace them with valid ones (if not search for invalid individual words)
    for (i = 0; i < words.length - 1; i++) {
        // Check for a pair of invalid words
        if (!allowedWords.includes(words[i]) && !allowedWords.includes(words[i+1])) {
            if ((words[i] + ' ' + words[i+1]) in corrections) {
                command += words[i] + ' ' + words[i+1] + ' ';
            }
        }
        // Check for individual invalid words if pairs aren't found
        else if (!allowedWords.includes(words[i])) {
            if (words[i] in corrections) {
                command += corrections[words[i]] + ' ';
            } else {
                if (!isNaN(words[i])) {
                    command += words[i] + ' ';
                    continue;
                }
                invalid = true;
                break;
            }
        }
        // Add the word to the command as it's an allowed word
        else {
            command += words[i] + ' ';
        }
    }

    // If all words in the command are valid and it's not the same as the previous value (if there is one), then add
    // it as a possible corrected command
    if (!invalid) {
        if ((possibleCommands.length > 0 && command != possibleCommands[0]) || possibleCommands.length == 0) {
            possibleCommands.push(command.trim());
        }
    }

    return possibleCommands;
}<|endoftext|>


<commit_before>/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";
// Components.utils.import("resource://gre/modules/NetUtil.jsm");
//let wantLogging = true;
/**
 * An adapter that handles data transfers between the debugger client and
 * server. It can work with both nsIPipe and nsIServerSocket transports so
 * long as the properly created input and output streams are specified.
 * (However, for intra-process connections, LocalDebuggerTransport, below,
 * is more efficient than using an nsIPipe pair with DebuggerTransport.)
 *
 * @param aInput nsIInputStream
 *        The input stream.
 * @param aOutput nsIAsyncOutputStream
 *        The output stream.
 *
 * Given a DebuggerTransport instance dt:
 * 1) Set dt.hooks to a packet handler object (described below).
 * 2) Call dt.ready() to begin watching for input packets.
 * 3) Call dt.send() to send packets as you please, and handle incoming
 *    packets passed to hook.onPacket.
 * 4) Call dt.close() to close the connection, and disengage from the event
 *    loop.
 *
 * A packet handler is an object with two methods:
 *
 * - onPacket(packet) - called when we have received a complete packet.
 *   |Packet| is the parsed form of the packet --- a JavaScript value, not
 *   a JSON-syntax string.
 *
 * - onClosed(status) - called when the connection is closed. |Status| is
 *   an nsresult, of the sort passed to nsIRequestObserver.
 *
 * Data is transferred as a JSON packet serialized into a string, with the
 * string length prepended to the packet, followed by a colon
 * ([length]:[packet]). The contents of the JSON packet are specified in
 * the Remote Debugging Protocol specification.
 */
this.DebuggerTransport = function DebuggerTransport(aInput, aOutput)
{
  this._input = aInput;
  this._output = aOutput;

  this._converter = null;//Cc["@mozilla.org/intl/scriptableunicodeconverter"]
    // .createInstance(Ci.nsIScriptableUnicodeConverter);
  // this._converter.charset = "UTF-8";

  this._outgoing = "";
  this._incoming = "";

  this.hooks = null;
}

DebuggerTransport.prototype = {
  /**
   * Transmit a packet.
   *
   * This method returns immediately, without waiting for the entire
   * packet to be transmitted, registering event handlers as needed to
   * transmit the entire packet. Packets are transmitted in the order
   * they are passed to this method.
   */
  send: function DT_send(aPacket) {
    let data = JSON.stringify(aPacket);
    // data = this._converter.ConvertFromUnicode(data);

    let data_for_len = utf16to8(data);

    this._outgoing = data_for_len.length + ':' + data_for_len;

    this._flushOutgoing();
  },

  /**
   * Close the transport.
   */
  close: function DT_close() {
    this._input.close();
    this._output.close();
  },

  /**
   * Flush the outgoing stream.
   */
  _flushOutgoing: function DT_flushOutgoing() {
    if (this._outgoing.length > 0) {
      // var threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
      // this._output.asyncWait(this, 0, 0, threadManager.currentThread);
      if (wantLogging) {
        log("outgoing: " + this._outgoing);//.substring(0, 200));
      };
      _bufferWrite(this._outgoing);
    }
  },

  onOutputStreamReady:
  makeInfallible(function DT_onOutputStreamReady(aStream) {
    let written = 0;
    try {
      written = aStream.write(this._outgoing, this._outgoing.length);
    } catch(e if e.result == Components.results.NS_BASE_STREAM_CLOSED) {
      dumpn("Connection closed.");
      this.close();
      return;
    }
    this._outgoing = this._outgoing.slice(written);
    this._flushOutgoing();
  }, "DebuggerTransport.prototype.onOutputStreamReady"),

  /**
   * Initialize the input stream for reading. Once this method has been
   * called, we watch for packets on the input stream, and pass them to
   * this.hook.onPacket.
   */
  ready: function DT_ready() {
    // let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
    //   .createInstance(Ci.nsIInputStreamPump);
    // pump.init(this._input, -1, -1, 0, 0, false);
    // pump.asyncRead(this, null);
  },

  // nsIStreamListener
  onStartRequest:
  makeInfallible(function DT_onStartRequest(aRequest, aContext) {},
                 "DebuggerTransport.prototype.onStartRequest"),

  onStopRequest:
  makeInfallible(function DT_onStopRequest(aRequest, aContext, aStatus) {
    this.close();
    if (this.hooks) {
      this.hooks.onClosed(aStatus);
      this.hooks = null;
    }
  }, "DebuggerTransport.prototype.onStopRequest"),

  onDataAvailable: makeInfallible(function DT_onDataAvailable (incoming)
//  makeInfallible(function DT_onDataAvailable(aRequest, aContext,
//                                             aStream, aOffset, aCount)
  {
    this._incoming = incoming;//+= NetUtil.readInputStreamToString(aStream,
                               //                       aStream.available());
    while (this._processIncoming()) {};
  }, "DebuggerTransport.prototype.onDataAvailable"),

  /**
   * Process incoming packets. Returns true if a packet has been received, either
   * if it was properly parsed or not. Returns false if the incoming stream does
   * not contain a full packet yet. After a proper packet is parsed, the dispatch
   * handler DebuggerTransport.hooks.onPacket is called with the packet as a
   * parameter.
   */
  _processIncoming: function DT__processIncoming() {
    // Well this is ugly.
    let sep = this._incoming.indexOf(':');
    if (sep < 0) {
      // Incoming packet length is too big anyway - drop the connection.
      if (this._incoming.length > 20) {
        this.close();
      }
      return false;
    }

    let count = this._incoming.substring(0, sep);
    // Check for a positive number with no garbage afterwards.
    if (!/^[0-9]+$/.exec(count)) {
      this.close();
      return false;
    }

    count = +count;
    if (this._incoming.length - (sep + 1) < count) {
      // Don't have a complete request yet.
      return false;
    }

    // We have a complete request, pluck it out of the data and parse it.
    this._incoming = this._incoming.substring(sep + 1);
    let packet = this._incoming.substring(0, count);
    this._incoming = this._incoming.substring(count);

    try {
      // packet = this._converter.ConvertToUnicode(packet);
      packet = utf8to16(packet);
      var parsed = JSON.parse(packet);
    } catch(e) {
      let msg = "Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")";
      // if (Cu.reportError) {
      //   Cu.reportError(msg);
      // }
      dump(msg + "\n");
      return true;
    }

    if (wantLogging) {
      dumpn("Got: " + JSON.stringify(parsed, null, 2));
    }

    let self = this;

    // Services.tm.currentThread.dispatch(makeInfallible(function() {
    // Ensure the hooks are still around by the time this runs (they will go
    // away when the transport is closed).
      if (self.hooks) {
        self.hooks.onPacket(parsed);
      }
    // }, "DebuggerTransport instance's this.hooks.onPacket"), 0);

    return true;
  }
}

/**
 * An adapter that handles data transfers between the debugger client and
 * server when they both run in the same process. It presents the same API as
 * DebuggerTransport, but instead of transmitting serialized messages across a
 * connection it merely calls the packet dispatcher of the other side.
 *
 * @param aOther LocalDebuggerTransport
 *        The other endpoint for this debugger connection.
 *
 * @see DebuggerTransport
 */
this.LocalDebuggerTransport = function LocalDebuggerTransport(aOther)
{
  this.other = aOther;
  this.hooks = null;

  /*
   * A packet number, shared between this and this.other. This isn't used
   * by the protocol at all, but it makes the packet traces a lot easier to
   * follow.
   */
  this._serial = this.other ? this.other._serial : { count: 0 };
}

LocalDebuggerTransport.prototype = {
  /**
   * Transmit a message by directly calling the onPacket handler of the other
   * endpoint.
   */
  send: function LDT_send(aPacket) {
    let serial = this._serial.count++;
    if (wantLogging) {
      /* Check 'from' first, as 'echo' packets have both. */
      if (aPacket.from) {
        dumpn("Packet " + serial + " sent from " + uneval(aPacket.from));
      } else if (aPacket.to) {
        dumpn("Packet " + serial + " sent to " + uneval(aPacket.to));
      }
    }
    this._deepFreeze(aPacket);
    let other = this.other;
    if (other) {
      Services.tm.currentThread.dispatch(makeInfallible(function() {
        // Avoid the cost of JSON.stringify() when logging is disabled.
        if (wantLogging) {
          dumpn("Received packet " + serial + ": " + JSON.stringify(aPacket, null, 2));
        }
        if (other.hooks) {
          other.hooks.onPacket(aPacket);
        }
      }, "LocalDebuggerTransport instance's this.other.hooks.onPacket"), 0);
    }
  },

  /**
   * Close the transport.
   */
  close: function LDT_close() {
    if (this.other) {
      // Remove the reference to the other endpoint before calling close(), to
      // avoid infinite recursion.
      let other = this.other;
      this.other = null;
      other.close();
    }
    if (this.hooks) {
      try {
        this.hooks.onClosed();
      } catch(ex) {
        Components.utils.reportError(ex);
      }
      this.hooks = null;
    }
  },

  /**
   * An empty method for emulating the DebuggerTransport API.
   */
  ready: function LDT_ready() {},

  /**
   * Helper function that makes an object fully immutable.
   */
  _deepFreeze: function LDT_deepFreeze(aObject) {
    Object.freeze(aObject);
    for (let prop in aObject) {
      // Freeze the properties that are objects, not on the prototype, and not
      // already frozen. Note that this might leave an unfrozen reference
      // somewhere in the object if there is an already frozen object containing
      // an unfrozen object.
      if (aObject.hasOwnProperty(prop) && typeof aObject === "object" &&
          !Object.isFrozen(aObject)) {
        this._deepFreeze(o[prop]);
      }
    }
  }
};

/**
 * A transport for the debugging protocol that uses nsIMessageSenders to
 * exchange packets with servers running in child processes.
 *
 * In the parent process, |aSender| should be the nsIMessageSender for the
 * child process. In a child process, |aSender| should be the child process
 * message manager, which sends packets to the parent.
 *
 * aPrefix is a string included in the message names, to distinguish
 * multiple servers running in the same child process.
 *
 * This transport exchanges messages named 'debug:<prefix>:packet', where
 * <prefix> is |aPrefix|, whose data is the protocol packet.
 */
function ChildDebuggerTransport(aSender, aPrefix) {
  this._sender = aSender.QueryInterface(Components.interfaces.nsIMessageSender);
  this._messageName = "debug:" + aPrefix + ":packet";
}

/*
 * To avoid confusion, we use 'message' to mean something that
 * nsIMessageSender conveys, and 'packet' to mean a remote debugging
 * protocol packet.
 */
ChildDebuggerTransport.prototype = {
  constructor: ChildDebuggerTransport,

  hooks: null,

  ready: function () {
    this._sender.addMessageListener(this._messageName, this);
  },

  close: function () {
    this._sender.removeMessageListener(this._messageName, this);
    this.hooks.onClosed();
  },

  receiveMessage: function ({data}) {
    this.hooks.onPacket(data);
  },

  send: function (packet) {
    this._sender.sendAsyncMessage(this._messageName, packet);
  }
};
<commit_msg>fix encoding<commit_after>/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";
// Components.utils.import("resource://gre/modules/NetUtil.jsm");
//let wantLogging = true;
/**
 * An adapter that handles data transfers between the debugger client and
 * server. It can work with both nsIPipe and nsIServerSocket transports so
 * long as the properly created input and output streams are specified.
 * (However, for intra-process connections, LocalDebuggerTransport, below,
 * is more efficient than using an nsIPipe pair with DebuggerTransport.)
 *
 * @param aInput nsIInputStream
 *        The input stream.
 * @param aOutput nsIAsyncOutputStream
 *        The output stream.
 *
 * Given a DebuggerTransport instance dt:
 * 1) Set dt.hooks to a packet handler object (described below).
 * 2) Call dt.ready() to begin watching for input packets.
 * 3) Call dt.send() to send packets as you please, and handle incoming
 *    packets passed to hook.onPacket.
 * 4) Call dt.close() to close the connection, and disengage from the event
 *    loop.
 *
 * A packet handler is an object with two methods:
 *
 * - onPacket(packet) - called when we have received a complete packet.
 *   |Packet| is the parsed form of the packet --- a JavaScript value, not
 *   a JSON-syntax string.
 *
 * - onClosed(status) - called when the connection is closed. |Status| is
 *   an nsresult, of the sort passed to nsIRequestObserver.
 *
 * Data is transferred as a JSON packet serialized into a string, with the
 * string length prepended to the packet, followed by a colon
 * ([length]:[packet]). The contents of the JSON packet are specified in
 * the Remote Debugging Protocol specification.
 */
this.DebuggerTransport = function DebuggerTransport(aInput, aOutput)
{
  this._input = aInput;
  this._output = aOutput;

  this._converter = null;//Cc["@mozilla.org/intl/scriptableunicodeconverter"]
    // .createInstance(Ci.nsIScriptableUnicodeConverter);
  // this._converter.charset = "UTF-8";

  this._outgoing = "";
  this._incoming = "";

  this.hooks = null;
}

DebuggerTransport.prototype = {
  /**
   * Transmit a packet.
   *
   * This method returns immediately, without waiting for the entire
   * packet to be transmitted, registering event handlers as needed to
   * transmit the entire packet. Packets are transmitted in the order
   * they are passed to this method.
   */
  send: function DT_send(aPacket) {
    let data = JSON.stringify(aPacket);
    // data = this._converter.ConvertFromUnicode(data);

    let data_for_len = utf16to8(data);

    this._outgoing = data_for_len.length + ':' + (cc.sys.os == cc.sys.OS_WINDOWS ? data_for_len : data);

    this._flushOutgoing();
  },

  /**
   * Close the transport.
   */
  close: function DT_close() {
    this._input.close();
    this._output.close();
  },

  /**
   * Flush the outgoing stream.
   */
  _flushOutgoing: function DT_flushOutgoing() {
    if (this._outgoing.length > 0) {
      // var threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
      // this._output.asyncWait(this, 0, 0, threadManager.currentThread);
      if (wantLogging) {
        log("outgoing: " + this._outgoing);//.substring(0, 200));
      };
      _bufferWrite(this._outgoing);
    }
  },

  onOutputStreamReady:
  makeInfallible(function DT_onOutputStreamReady(aStream) {
    let written = 0;
    try {
      written = aStream.write(this._outgoing, this._outgoing.length);
    } catch(e if e.result == Components.results.NS_BASE_STREAM_CLOSED) {
      dumpn("Connection closed.");
      this.close();
      return;
    }
    this._outgoing = this._outgoing.slice(written);
    this._flushOutgoing();
  }, "DebuggerTransport.prototype.onOutputStreamReady"),

  /**
   * Initialize the input stream for reading. Once this method has been
   * called, we watch for packets on the input stream, and pass them to
   * this.hook.onPacket.
   */
  ready: function DT_ready() {
    // let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
    //   .createInstance(Ci.nsIInputStreamPump);
    // pump.init(this._input, -1, -1, 0, 0, false);
    // pump.asyncRead(this, null);
  },

  // nsIStreamListener
  onStartRequest:
  makeInfallible(function DT_onStartRequest(aRequest, aContext) {},
                 "DebuggerTransport.prototype.onStartRequest"),

  onStopRequest:
  makeInfallible(function DT_onStopRequest(aRequest, aContext, aStatus) {
    this.close();
    if (this.hooks) {
      this.hooks.onClosed(aStatus);
      this.hooks = null;
    }
  }, "DebuggerTransport.prototype.onStopRequest"),

  onDataAvailable: makeInfallible(function DT_onDataAvailable (incoming)
//  makeInfallible(function DT_onDataAvailable(aRequest, aContext,
//                                             aStream, aOffset, aCount)
  {
    this._incoming = incoming;//+= NetUtil.readInputStreamToString(aStream,
                               //                       aStream.available());
    while (this._processIncoming()) {};
  }, "DebuggerTransport.prototype.onDataAvailable"),

  /**
   * Process incoming packets. Returns true if a packet has been received, either
   * if it was properly parsed or not. Returns false if the incoming stream does
   * not contain a full packet yet. After a proper packet is parsed, the dispatch
   * handler DebuggerTransport.hooks.onPacket is called with the packet as a
   * parameter.
   */
  _processIncoming: function DT__processIncoming() {
    // Well this is ugly.
    let sep = this._incoming.indexOf(':');
    if (sep < 0) {
      // Incoming packet length is too big anyway - drop the connection.
      if (this._incoming.length > 20) {
        this.close();
      }
      return false;
    }

    let count = this._incoming.substring(0, sep);
    // Check for a positive number with no garbage afterwards.
    if (!/^[0-9]+$/.exec(count)) {
      this.close();
      return false;
    }

    count = +count;
    if (this._incoming.length - (sep + 1) < count) {
      // Don't have a complete request yet.
      return false;
    }

    // We have a complete request, pluck it out of the data and parse it.
    this._incoming = this._incoming.substring(sep + 1);
    let packet = this._incoming.substring(0, count);
    this._incoming = this._incoming.substring(count);

    try {
      // packet = this._converter.ConvertToUnicode(packet);
      packet = utf8to16(packet);
      var parsed = JSON.parse(packet);
    } catch(e) {
      let msg = "Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")";
      // if (Cu.reportError) {
      //   Cu.reportError(msg);
      // }
      dump(msg + "\n");
      return true;
    }

    if (wantLogging) {
      dumpn("Got: " + JSON.stringify(parsed, null, 2));
    }

    let self = this;

    // Services.tm.currentThread.dispatch(makeInfallible(function() {
    // Ensure the hooks are still around by the time this runs (they will go
    // away when the transport is closed).
      if (self.hooks) {
        self.hooks.onPacket(parsed);
      }
    // }, "DebuggerTransport instance's this.hooks.onPacket"), 0);

    return true;
  }
}

/**
 * An adapter that handles data transfers between the debugger client and
 * server when they both run in the same process. It presents the same API as
 * DebuggerTransport, but instead of transmitting serialized messages across a
 * connection it merely calls the packet dispatcher of the other side.
 *
 * @param aOther LocalDebuggerTransport
 *        The other endpoint for this debugger connection.
 *
 * @see DebuggerTransport
 */
this.LocalDebuggerTransport = function LocalDebuggerTransport(aOther)
{
  this.other = aOther;
  this.hooks = null;

  /*
   * A packet number, shared between this and this.other. This isn't used
   * by the protocol at all, but it makes the packet traces a lot easier to
   * follow.
   */
  this._serial = this.other ? this.other._serial : { count: 0 };
}

LocalDebuggerTransport.prototype = {
  /**
   * Transmit a message by directly calling the onPacket handler of the other
   * endpoint.
   */
  send: function LDT_send(aPacket) {
    let serial = this._serial.count++;
    if (wantLogging) {
      /* Check 'from' first, as 'echo' packets have both. */
      if (aPacket.from) {
        dumpn("Packet " + serial + " sent from " + uneval(aPacket.from));
      } else if (aPacket.to) {
        dumpn("Packet " + serial + " sent to " + uneval(aPacket.to));
      }
    }
    this._deepFreeze(aPacket);
    let other = this.other;
    if (other) {
      Services.tm.currentThread.dispatch(makeInfallible(function() {
        // Avoid the cost of JSON.stringify() when logging is disabled.
        if (wantLogging) {
          dumpn("Received packet " + serial + ": " + JSON.stringify(aPacket, null, 2));
        }
        if (other.hooks) {
          other.hooks.onPacket(aPacket);
        }
      }, "LocalDebuggerTransport instance's this.other.hooks.onPacket"), 0);
    }
  },

  /**
   * Close the transport.
   */
  close: function LDT_close() {
    if (this.other) {
      // Remove the reference to the other endpoint before calling close(), to
      // avoid infinite recursion.
      let other = this.other;
      this.other = null;
      other.close();
    }
    if (this.hooks) {
      try {
        this.hooks.onClosed();
      } catch(ex) {
        Components.utils.reportError(ex);
      }
      this.hooks = null;
    }
  },

  /**
   * An empty method for emulating the DebuggerTransport API.
   */
  ready: function LDT_ready() {},

  /**
   * Helper function that makes an object fully immutable.
   */
  _deepFreeze: function LDT_deepFreeze(aObject) {
    Object.freeze(aObject);
    for (let prop in aObject) {
      // Freeze the properties that are objects, not on the prototype, and not
      // already frozen. Note that this might leave an unfrozen reference
      // somewhere in the object if there is an already frozen object containing
      // an unfrozen object.
      if (aObject.hasOwnProperty(prop) && typeof aObject === "object" &&
          !Object.isFrozen(aObject)) {
        this._deepFreeze(o[prop]);
      }
    }
  }
};

/**
 * A transport for the debugging protocol that uses nsIMessageSenders to
 * exchange packets with servers running in child processes.
 *
 * In the parent process, |aSender| should be the nsIMessageSender for the
 * child process. In a child process, |aSender| should be the child process
 * message manager, which sends packets to the parent.
 *
 * aPrefix is a string included in the message names, to distinguish
 * multiple servers running in the same child process.
 *
 * This transport exchanges messages named 'debug:<prefix>:packet', where
 * <prefix> is |aPrefix|, whose data is the protocol packet.
 */
function ChildDebuggerTransport(aSender, aPrefix) {
  this._sender = aSender.QueryInterface(Components.interfaces.nsIMessageSender);
  this._messageName = "debug:" + aPrefix + ":packet";
}

/*
 * To avoid confusion, we use 'message' to mean something that
 * nsIMessageSender conveys, and 'packet' to mean a remote debugging
 * protocol packet.
 */
ChildDebuggerTransport.prototype = {
  constructor: ChildDebuggerTransport,

  hooks: null,

  ready: function () {
    this._sender.addMessageListener(this._messageName, this);
  },

  close: function () {
    this._sender.removeMessageListener(this._messageName, this);
    this.hooks.onClosed();
  },

  receiveMessage: function ({data}) {
    this.hooks.onPacket(data);
  },

  send: function (packet) {
    this._sender.sendAsyncMessage(this._messageName, packet);
  }
};
<|endoftext|>