<commit_before>'use strict';

/**
 * The entry point for mountebank.  This module creates the mountebank server,
 * configures all middleware, starts the logger, and manages all routing
 * @module
 */

var Q = require('q'),
    express = require('express'),
    cors = require('cors'),
    errorHandler = require('errorhandler'),
    path = require('path'),
    fs = require('fs'),
    middleware = require('./util/middleware'),
    HomeController = require('./controllers/homeController'),
    ImpostersController = require('./controllers/impostersController'),
    ImposterController = require('./controllers/imposterController'),
    LogsController = require('./controllers/logsController'),
    ConfigController = require('./controllers/configController'),
    FeedController = require('./controllers/feedController'),
    Imposter = require('./models/imposter'),
    winston = require('winston'),
    thisPackage = require('../package.json'),
    releases = require('../releases.json'),
    ScopedLogger = require('./util/scopedLogger'),
    util = require('util');

function initializeLogfile (filename) {
    // Ensure new logfile on startup so the /logs only shows for this process
    var extension = path.extname(filename),
        pattern = new RegExp(extension + '$'),
        newFilename = filename.replace(pattern, '1' + extension);

    if (fs.existsSync(filename)) {
        fs.renameSync(filename, newFilename);
    }
}

/**
 * Creates the mountebank server
 * @param {object} options - The command line options
 * @returns {Object} An object with a close method to stop the server
 */
function create (options) {
    var deferred = Q.defer(),
        app = express(),
        imposters = {},
        protocols = {
            tcp: require('./models/tcp/tcpServer').initialize(options.allowInjection, options.mock, options.debug),
            http: require('./models/http/httpServer').initialize(options.allowInjection, options.mock, options.debug),
            https: require('./models/https/httpsServer').initialize(options.allowInjection, options.mock, options.debug),
            soap: require('./models/soap/soapServer').initialize(options.allowInjection, options.mock, options.debug),
            smtp: require('./models/smtp/smtpServer').initialize(options.mock, options.debug),
            foo: require('./models/foo/fooServer').initialize(options.allowInjection, options.mock, options.debug)
        },
        logger = ScopedLogger.create(winston, util.format('[mb:%s] ', options.port)),
        homeController = HomeController.create(releases),
        impostersController = ImpostersController.create(protocols, imposters, Imposter, logger),
        imposterController = ImposterController.create(imposters),
        logsController = LogsController.create(options.logfile),
        configController = ConfigController.create(thisPackage.version, options),
        feedController = FeedController.create(releases, options),
        validateImposterExists = middleware.createImposterValidator(imposters),
        welcome = util.format('mountebank v%s (node %s) now taking orders - point your browser to http://localhost:%s for help',
            thisPackage.version, process.version, options.port);

    logger.remove(logger.transports.Console);
    if (process.stdout.isTTY) {
        logger.add(logger.transports.Console, { colorize: true, level: options.loglevel });
    }
    initializeLogfile(options.logfile);
    logger.add(logger.transports.File, {
        filename: options.logfile,
        timestamp: true,
        level: options.loglevel,
        maxsize: 10000000,
        maxFiles: 1
    });

    app.use(middleware.useAbsoluteUrls(options.port));
    app.use(middleware.logger(logger, ':method :url'));
    app.use(middleware.globals({ heroku: options.heroku, port: options.port, version: thisPackage.version }));
    app.use(middleware.defaultIEtoHTML);
    app.use(middleware.json(logger));
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(express.static(path.join(__dirname, '../node_modules')));
    app.use(errorHandler());
    if (options.allowCORS) {
        app.use(cors());
    }

    app.disable('etag');
    app.disable('x-powered-by');
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    app.set('json spaces', 2);

    app.get('/', homeController.get);
    app.get('/imposters', impostersController.get);
    app.post('/imposters', impostersController.post);
    app.delete('/imposters', impostersController.del);
    app.put('/imposters', impostersController.put);
    app.get('/imposters/:id', validateImposterExists, imposterController.get);
    app.delete('/imposters/:id', imposterController.del);
    app.get('/logs', logsController.get);
    app.get('/config', configController.get);
    app.get('/feed', feedController.getFeed);
    app.get('/releases', feedController.getReleases);
    app.get('/releases/:version', feedController.getRelease);

    app.get('/sitemap', function (request, response) {
        response.type('text/plain');
        response.render('sitemap', { releases: releases });
    });

    [
        '/support',
        '/license',
        '/faqs',
        '/thoughtworks',
        '/docs/examples',
        '/docs/gettingStarted',
        '/docs/install',
        '/docs/glossary',
        '/docs/commandLine',
        '/docs/clientLibraries',
        '/docs/api/overview',
        '/docs/api/contracts',
        '/docs/api/mocks',
        '/docs/api/stubs',
        '/docs/api/predicates',
        '/docs/api/xpath',
        '/docs/api/proxies',
        '/docs/api/injection',
        '/docs/api/behaviors',
        '/docs/api/errors',
        '/docs/protocols/http',
        '/docs/protocols/https',
        '/docs/protocols/tcp',
        '/docs/protocols/smtp'
    ].forEach(function (endpoint) {
        app.get(endpoint, function (request, response) {
            response.render(endpoint.substring(1));
        });
    });

    var server = app.listen(options.port, function () {
        logger.info(welcome);
        deferred.resolve({
            close: function (callback) {
                server.close(function () {
                    logger.info('Adios - see you soon?');
                    callback();
                });
            }
        });
    });

    return deferred.promise;
}

module.exports = {
    create: create
};
<commit_msg>Adding additional debug information on startup for support<commit_after>'use strict';

/**
 * The entry point for mountebank.  This module creates the mountebank server,
 * configures all middleware, starts the logger, and manages all routing
 * @module
 */

var Q = require('q'),
    express = require('express'),
    cors = require('cors'),
    errorHandler = require('errorhandler'),
    path = require('path'),
    fs = require('fs'),
    middleware = require('./util/middleware'),
    HomeController = require('./controllers/homeController'),
    ImpostersController = require('./controllers/impostersController'),
    ImposterController = require('./controllers/imposterController'),
    LogsController = require('./controllers/logsController'),
    ConfigController = require('./controllers/configController'),
    FeedController = require('./controllers/feedController'),
    Imposter = require('./models/imposter'),
    winston = require('winston'),
    thisPackage = require('../package.json'),
    releases = require('../releases.json'),
    ScopedLogger = require('./util/scopedLogger'),
    util = require('util');

function initializeLogfile (filename) {
    // Ensure new logfile on startup so the /logs only shows for this process
    var extension = path.extname(filename),
        pattern = new RegExp(extension + '$'),
        newFilename = filename.replace(pattern, '1' + extension);

    if (fs.existsSync(filename)) {
        fs.renameSync(filename, newFilename);
    }
}

/**
 * Creates the mountebank server
 * @param {object} options - The command line options
 * @returns {Object} An object with a close method to stop the server
 */
function create (options) {
    var deferred = Q.defer(),
        app = express(),
        imposters = {},
        protocols = {
            tcp: require('./models/tcp/tcpServer').initialize(options.allowInjection, options.mock, options.debug),
            http: require('./models/http/httpServer').initialize(options.allowInjection, options.mock, options.debug),
            https: require('./models/https/httpsServer').initialize(options.allowInjection, options.mock, options.debug),
            soap: require('./models/soap/soapServer').initialize(options.allowInjection, options.mock, options.debug),
            smtp: require('./models/smtp/smtpServer').initialize(options.mock, options.debug),
            foo: require('./models/foo/fooServer').initialize(options.allowInjection, options.mock, options.debug)
        },
        logger = ScopedLogger.create(winston, util.format('[mb:%s] ', options.port)),
        homeController = HomeController.create(releases),
        impostersController = ImpostersController.create(protocols, imposters, Imposter, logger),
        imposterController = ImposterController.create(imposters),
        logsController = LogsController.create(options.logfile),
        configController = ConfigController.create(thisPackage.version, options),
        feedController = FeedController.create(releases, options),
        validateImposterExists = middleware.createImposterValidator(imposters);
    logger.remove(logger.transports.Console);
    if (process.stdout.isTTY) {
        logger.add(logger.transports.Console, { colorize: true, level: options.loglevel });
    }
    initializeLogfile(options.logfile);
    logger.add(logger.transports.File, {
        filename: options.logfile,
        timestamp: true,
        level: options.loglevel,
        maxsize: 10000000,
        maxFiles: 1
    });

    app.use(middleware.useAbsoluteUrls(options.port));
    app.use(middleware.logger(logger, ':method :url'));
    app.use(middleware.globals({ heroku: options.heroku, port: options.port, version: thisPackage.version }));
    app.use(middleware.defaultIEtoHTML);
    app.use(middleware.json(logger));
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(express.static(path.join(__dirname, '../node_modules')));
    app.use(errorHandler());
    if (options.allowCORS) {
        app.use(cors());
    }

    app.disable('etag');
    app.disable('x-powered-by');
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    app.set('json spaces', 2);

    app.get('/', homeController.get);
    app.get('/imposters', impostersController.get);
    app.post('/imposters', impostersController.post);
    app.delete('/imposters', impostersController.del);
    app.put('/imposters', impostersController.put);
    app.get('/imposters/:id', validateImposterExists, imposterController.get);
    app.delete('/imposters/:id', imposterController.del);
    app.get('/logs', logsController.get);
    app.get('/config', configController.get);
    app.get('/feed', feedController.getFeed);
    app.get('/releases', feedController.getReleases);
    app.get('/releases/:version', feedController.getRelease);

    app.get('/sitemap', function (request, response) {
        response.type('text/plain');
        response.render('sitemap', { releases: releases });
    });

    [
        '/support',
        '/license',
        '/faqs',
        '/thoughtworks',
        '/docs/examples',
        '/docs/gettingStarted',
        '/docs/install',
        '/docs/glossary',
        '/docs/commandLine',
        '/docs/clientLibraries',
        '/docs/api/overview',
        '/docs/api/contracts',
        '/docs/api/mocks',
        '/docs/api/stubs',
        '/docs/api/predicates',
        '/docs/api/xpath',
        '/docs/api/proxies',
        '/docs/api/injection',
        '/docs/api/behaviors',
        '/docs/api/errors',
        '/docs/protocols/http',
        '/docs/protocols/https',
        '/docs/protocols/tcp',
        '/docs/protocols/smtp'
    ].forEach(function (endpoint) {
        app.get(endpoint, function (request, response) {
            response.render(endpoint.substring(1));
        });
    });

    var server = app.listen(options.port, function () {
        logger.info(util.format('mountebank v%s now taking orders - point your browser to http://localhost:%s for help',
            thisPackage.version, options.port));
        logger.debug('config: ' + JSON.stringify({
                options: options,
                process: {
                    nodeVersion: process.version,
                    architecture: process.arch,
                    platform: process.platform
                }
            })
        );
        deferred.resolve({
            close: function (callback) {
                server.close(function () {
                    logger.info('Adios - see you soon?');
                    callback();
                });
            }
        });
    });

    return deferred.promise;
}

module.exports = {
    create: create
};
<|endoftext|>


<commit_before>var walkSync = require('walk-sync');
var Petal = require('petal');
var fs = require('fs');
var helpers = require('broccoli-kitchen-sink-helpers');
var RSVP = require('rsvp');
var rimraf = RSVP.denodeify(require('rimraf'));
var symlinkOrCopy = require('symlink-or-copy');
var CachingWriter = require('broccoli-caching-writer');

module.exports = CachingWriter.extend({
  init: function(){
    this.enforceSingleInputTree = true;

    // The petalCache lets us avoid re-parsing individual files that
    // haven't changed.
    this.petalCache = {};

    // The stubsCache lets us avoid re-running browserify when the set
    // of included modules hasn't changed.
    this.stubsCache = {};
  },

  read: function(readTree) {
    var self = this;
    return readTree(this.inputTrees[0]).then(function(srcDir){
      var paths = walkSync(srcDir);
      var stubs = {};
      var updateCacheResult;
      paths.forEach(function (relativePath) {
        if (relativePath.slice(-3) === '.js') {
          gatherStubs(srcDir, relativePath, stubs, self.petalCache);
        }
      });
      if (!sameStubs(stubs, self.stubsCache)) {
        self.stubsCache = stubs;
        updateCacheResult = self.updateCache(srcDir, self.getCleanCacheDir());
      }
      return updateCacheResult;
    }).then(function(){
      return rimraf(self._destDir);
    }).then(function(){
      symlinkOrCopy.sync(self.getCacheDir(), self._destDir);
    }).then(function(){
      return self._destDir;
    });
  },

  updateCache: function(srcDir, destDir) {
    fs.writeFileSync(destDir + '/browserify_stubs.js', generate(this.stubsCache));
    return destDir;
  }
});

function gatherStubs(srcDir, relativePath, stubs, cache) {
  var src = fs.readFileSync(srcDir + '/' + relativePath);
  var key = helpers.hashStrings([relativePath, src]);

  if (cache[key]) {
    var len = cache[key].length;
    for (var i=0; i<len; i++) {
      stubs[cache[key][i]] = true;
    }
    return;
  }

  var cacheEntry = cache[key] = [];
  var petal = new Petal(relativePath, src);
  Object.keys(petal.imports).forEach(function(key){
    if (key.slice(0,4) === 'npm:') {
      var moduleName = key.slice(4);
      stubs[moduleName] = true;
      cacheEntry.push(moduleName);
    }
  });
}

function generate(stubs) {
  return Object.keys(stubs).map(function(moduleName){
    return "define('npm:" +
      moduleName +
      "', function(){ return { default: require('" +
      moduleName +
      "')};})";
  }).join("\n");
}

function sameStubs(a, b) {
  var keys = Object.keys(a);
  for (var i=0; i < keys.length; i++) {
    if (!b[keys[i]]) {
      return false;
    }
  }
  keys = Object.keys(b);
  for (i=0; i < keys.length; i++) {
    if (!a[keys[i]]) {
      return false;
    }
  }
  return true;
}
<commit_msg>bugfix: don't break on initial build when there are no npm imports<commit_after>var walkSync = require('walk-sync');
var Petal = require('petal');
var fs = require('fs');
var helpers = require('broccoli-kitchen-sink-helpers');
var RSVP = require('rsvp');
var rimraf = RSVP.denodeify(require('rimraf'));
var symlinkOrCopy = require('symlink-or-copy');
var CachingWriter = require('broccoli-caching-writer');

module.exports = CachingWriter.extend({
  init: function(){
    this.enforceSingleInputTree = true;

    // The petalCache lets us avoid re-parsing individual files that
    // haven't changed.
    this.petalCache = {};

    // The stubsCache lets us avoid re-running browserify when the set
    // of included modules hasn't changed.
    this.stubsCache = null;
  },

  read: function(readTree) {
    var self = this;
    return readTree(this.inputTrees[0]).then(function(srcDir){
      var paths = walkSync(srcDir);
      var stubs = {};
      var updateCacheResult;
      paths.forEach(function (relativePath) {
        if (relativePath.slice(-3) === '.js') {
          gatherStubs(srcDir, relativePath, stubs, self.petalCache);
        }
      });
      if (!sameStubs(stubs, self.stubsCache)) {
        self.stubsCache = stubs;
        updateCacheResult = self.updateCache(srcDir, self.getCleanCacheDir());
      }
      return updateCacheResult;
    }).then(function(){
      return rimraf(self._destDir);
    }).then(function(){
      symlinkOrCopy.sync(self.getCacheDir(), self._destDir);
    }).then(function(){
      return self._destDir;
    });
  },

  updateCache: function(srcDir, destDir) {
    fs.writeFileSync(destDir + '/browserify_stubs.js', generate(this.stubsCache));
    return destDir;
  }
});

function gatherStubs(srcDir, relativePath, stubs, cache) {
  var src = fs.readFileSync(srcDir + '/' + relativePath);
  var key = helpers.hashStrings([relativePath, src]);

  if (cache[key]) {
    var len = cache[key].length;
    for (var i=0; i<len; i++) {
      stubs[cache[key][i]] = true;
    }
    return;
  }

  var cacheEntry = cache[key] = [];
  var petal = new Petal(relativePath, src);
  Object.keys(petal.imports).forEach(function(key){
    if (key.slice(0,4) === 'npm:') {
      var moduleName = key.slice(4);
      stubs[moduleName] = true;
      cacheEntry.push(moduleName);
    }
  });
}

function generate(stubs) {
  return Object.keys(stubs).map(function(moduleName){
    return "define('npm:" +
      moduleName +
      "', function(){ return { default: require('" +
      moduleName +
      "')};})";
  }).join("\n");
}

function sameStubs(a, b) {
  if (!a || !b) {
    return false;
  }
  var keys = Object.keys(a);
  for (var i=0; i < keys.length; i++) {
    if (!b[keys[i]]) {
      return false;
    }
  }
  keys = Object.keys(b);
  for (i=0; i < keys.length; i++) {
    if (!a[keys[i]]) {
      return false;
    }
  }
  return true;
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
'use strict';

/**
 * @fileoverview Mutator test blocks.
 * @author samelh@google.com (Sam El-Husseini)
 */

import * as Blockly from 'blockly/core';

Blockly.defineBlocksWithJsonArray([
  {
    'type': 'test_mutators_noflyout',
    'message0': 'noflyout mutator',
    'mutator': 'test_noflyout_mutator',
    'colour': '#000000',
  },
  {
    'type': 'test_mutators_noflyout_block',
    'message0': 'colour %1',
    'args0': [
      {
        'type': 'field_colour',
        'name': 'COLOUR',
        'colour': '#ff0000',
      },
    ],
    'style': 'colour_blocks',
  },
]);

/**
 * Mutator methods added to the test_mutators_noflyout block.
 * @mixin
 * @augments Blockly.Block
 * @package
 * @readonly
 */
const NO_FLYOUT_MUTATOR = {
  /**
   * Create XML to represent the block mutation.
   * @return {Element} XML storage element.
   * @this {Blockly.Block}
   */
  mutationToDom: function() {
    const container = Blockly.utils.xml.createElement('mutation');
    container.setAttribute('colour', this.colour_);
    this.setColour(this.colour_);
    return container;
  },
  /**
   * Restore a block from XML.
   * @param {!Element} xmlElement XML storage element.
   * @this {Blockly.Block}
   */
  domToMutation: function(xmlElement) {
    this.colour_ = xmlElement.getAttribute('colour');
  },
  /**
   * Populate the mutator's dialog with this block's components.
   * @param {!Blockly.Workspace} workspace Mutator's workspace.
   * @return {!Blockly.Block} Root block in mutator.
   * @this {Blockly.Block}
   */
  decompose: function(workspace) {
    const containerBlock = workspace.newBlock('test_mutators_noflyout_block');
    containerBlock.getField('COLOUR').setValue(this.colour_);
    containerBlock.initSvg();
    return containerBlock;
  },
  /**
   * Reconfigure this block based on the mutator dialog's components.
   * @param {!Blockly.Block} containerBlock Root block in mutator.
   * @this {Blockly.Block}
   */
  compose: function(containerBlock) {
    this.colour_ = containerBlock.getFieldValue('COLOUR');
    this.setColour(this.colour_);
  },
};

/**
 * Register custom mutator used by the test_mutators_noflyout block.
 */
Blockly.Extensions.registerMutator(
    'test_noflyout_mutator', NO_FLYOUT_MUTATOR, null, []);

/**
 * The Mutators category.
 */
export const category = {
  'kind': 'CATEGORY',
  'name': 'Mutators',
  'contents': [
    {
      'kind': 'LABEL',
      'text': 'logic_compare',
    },
    {
      'kind': 'BLOCK',
      'blockxml': `
<block type="logic_compare">
  <value name="A">
    <shadow type="math_number">
      <field name="NUM">10</field>
    </shadow>
  </value>
  <value name="B">
    <shadow type="math_number">
      <field name="NUM">10</field>
    </shadow>
  </value>
</block>`,
    },
    {
      'kind': 'BLOCK',
      'blockxml': `
<block type="logic_compare">
  <value name="A">
    <block type="math_number">
      <field name="NUM">10</field>
    </block>
  </value>
  <value name="B">
    <block type="math_number">
      <field name="NUM">10</field>
    </block>
  </value>
</block>`,
    },
    {
      'kind': 'BLOCK',
      'type': 'test_mutators_noflyout',
    },
  ],
};

/**
 * Initialize this toolbox category.
 * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace.
 */
export function onInit(workspace) {
  // NOP
}
<commit_msg>Add long flyout mutator test block (#599)<commit_after>/**
 * @license
 * Copyright 2020 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
'use strict';

/**
 * @fileoverview Mutator test blocks.
 * @author samelh@google.com (Sam El-Husseini)
 */

import * as Blockly from 'blockly/core';

const n = 20;
const blocksIds = [];
for (let i = 0; i < n; i++) {
  blocksIds.push(`test_mutator_category_${i}`);
}

const defineBlocks = blocksIds.map((t) => ({
  type: t,
  message0: 'colour %1',
  args0: [
    {
      type: 'field_colour',
      name: 'COLOUR',
      colour: '#ff0000',
    },
  ],
  style: 'colour_blocks',
}));

Blockly.defineBlocksWithJsonArray([
  {
    type: 'test_mutators_many',
    message0: 'test many blocks mutator',
    mutator: 'test_many_blocks_mutator',
    colour: '#000000',
  },
  ...defineBlocks,
]);

/**
 * Mutator methods added to the test_mutators_many block.
 * @mixin
 * @augments Blockly.Block
 * @package
 * @readonly
 */
const MANY_BLOCKS_MUTATOR = {
  /**
   * Create XML to represent the block mutation.
   * @return {Element} XML storage element.
   * @this {Blockly.Block}
   */
  mutationToDom: function() {
    const container = Blockly.utils.xml.createElement('mutation');
    container.setAttribute('colour', this.colour_);
    this.setColour(this.colour_);
    return container;
  },
  /**
   * Restore a block from XML.
   * @param {!Element} xmlElement XML storage element.
   * @this {Blockly.Block}
   */
  domToMutation: function(xmlElement) {
    this.colour_ = xmlElement.getAttribute('colour');
  },
  /**
   * Populate the mutator's dialog with this block's components.
   * @param {!Blockly.Workspace} workspace Mutator's workspace.
   * @return {!Blockly.Block} Root block in mutator.
   * @this {Blockly.Block}
   */
  decompose: function(workspace) {
    const containerBlock = workspace.newBlock('test_mutators_noflyout_block');
    containerBlock.getField('COLOUR').setValue(this.colour_);
    containerBlock.initSvg();
    return containerBlock;
  },
  /**
   * Reconfigure this block based on the mutator dialog's components.
   * @param {!Blockly.Block} containerBlock Root block in mutator.
   * @this {Blockly.Block}
   */
  compose: function(containerBlock) {
    this.colour_ = containerBlock.getFieldValue('COLOUR');
    this.setColour(this.colour_);
  },
};

Blockly.Extensions.unregister('test_many_blocks_mutator');

/**
 * Register custom mutator used by the test_mutators_many block.
 */
Blockly.Extensions.registerMutator(
    'test_many_blocks_mutator',
    MANY_BLOCKS_MUTATOR,
    null,
    [...blocksIds]
);

Blockly.defineBlocksWithJsonArray([
  {
    'type': 'test_mutators_noflyout',
    'message0': 'noflyout mutator',
    'mutator': 'test_noflyout_mutator',
    'colour': '#000000',
  },
  {
    'type': 'test_mutators_noflyout_block',
    'message0': 'colour %1',
    'args0': [
      {
        'type': 'field_colour',
        'name': 'COLOUR',
        'colour': '#ff0000',
      },
    ],
    'style': 'colour_blocks',
  },
]);

/**
 * Mutator methods added to the test_mutators_noflyout block.
 * @mixin
 * @augments Blockly.Block
 * @package
 * @readonly
 */
const NO_FLYOUT_MUTATOR = {
  /**
   * Create XML to represent the block mutation.
   * @return {Element} XML storage element.
   * @this {Blockly.Block}
   */
  mutationToDom: function() {
    const container = Blockly.utils.xml.createElement('mutation');
    container.setAttribute('colour', this.colour_);
    this.setColour(this.colour_);
    return container;
  },
  /**
   * Restore a block from XML.
   * @param {!Element} xmlElement XML storage element.
   * @this {Blockly.Block}
   */
  domToMutation: function(xmlElement) {
    this.colour_ = xmlElement.getAttribute('colour');
  },
  /**
   * Populate the mutator's dialog with this block's components.
   * @param {!Blockly.Workspace} workspace Mutator's workspace.
   * @return {!Blockly.Block} Root block in mutator.
   * @this {Blockly.Block}
   */
  decompose: function(workspace) {
    const containerBlock = workspace.newBlock('test_mutators_noflyout_block');
    containerBlock.getField('COLOUR').setValue(this.colour_);
    containerBlock.initSvg();
    return containerBlock;
  },
  /**
   * Reconfigure this block based on the mutator dialog's components.
   * @param {!Blockly.Block} containerBlock Root block in mutator.
   * @this {Blockly.Block}
   */
  compose: function(containerBlock) {
    this.colour_ = containerBlock.getFieldValue('COLOUR');
    this.setColour(this.colour_);
  },
};

/**
 * Register custom mutator used by the test_mutators_noflyout block.
 */
Blockly.Extensions.registerMutator(
    'test_noflyout_mutator', NO_FLYOUT_MUTATOR, null, []);

/**
 * The Mutators category.
 */
export const category = {
  'kind': 'CATEGORY',
  'name': 'Mutators',
  'contents': [
    {
      'kind': 'LABEL',
      'text': 'logic_compare',
    },
    {
      'kind': 'BLOCK',
      'blockxml': `
<block type="logic_compare">
  <value name="A">
    <shadow type="math_number">
      <field name="NUM">10</field>
    </shadow>
  </value>
  <value name="B">
    <shadow type="math_number">
      <field name="NUM">10</field>
    </shadow>
  </value>
</block>`,
    },
    {
      'kind': 'BLOCK',
      'blockxml': `
<block type="logic_compare">
  <value name="A">
    <block type="math_number">
      <field name="NUM">10</field>
    </block>
  </value>
  <value name="B">
    <block type="math_number">
      <field name="NUM">10</field>
    </block>
  </value>
</block>`,
    },
    {
      'kind': 'BLOCK',
      'type': 'test_mutators_noflyout',
    },
    {
      'kind': 'BLOCK',
      'type': 'test_mutators_many',
    },
  ],
};

/**
 * Initialize this toolbox category.
 * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace.
 */
export function onInit(workspace) {
  // NOP
}
<|endoftext|>


<commit_before>//     myTemplate.js 0.2.0

//     (c) 2014 Guoyao Wu,
//     Backbone may be freely distributed under the BSD license.
//     For all details and documentation:
//     https://github.com/guoyao/myTemplate

(function(root, factory) {
    // Set up myTemplate appropriately for the environment. Start with AMD.
    if (typeof define === 'function' && define.amd) {
        define(function() {
            return factory(root);
        });
    // Next for Node.js or CommonJS.
    } else if (typeof exports !== 'undefined') {
        module.exports = factory(root);
    // Finally, as a browser global.
    } else {
        root.myTemplate = factory(root);
    }
}(this, function(root) {

    // Save the previous value of the `Backbone` variable, so that it can be
    // restored later on, if `noConflict` is used.
    var previousMyTemplate = root.myTemplate;

    /**
     * 模板引擎
     * @name    myTemplate
     * @param   {String}  模板字符串
     * @param   {Object}  数据
     * @return  {String, Function}  渲染好的HTML字符串或者渲染方法
     */
    var myTemplate = function template() {
        'use strict';

        var args = Array.prototype.slice.call(arguments),
            tmpl = args.shift().replace(/\r|\n/g, "").replace(/"/g, '\\"'), //转义"号
            funcBody = 'var result = "' + tmpl + '";',
            func;

        funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
            return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时，恢复<%=%>中被转义的"号
        });
        funcBody = funcBody.replace(/<%\s*([^>]*)\s*%>/g, function(match, $1) {
            return '";' + $1.replace(/\\"/g, '"') + 'result += "'; //替换的同时，恢复<%=%>中被转义的"号
        });

        funcBody += " return result;";

        func = new Function(funcBody);
        if (args.length > 0) {
            return func.apply(args.shift(), args); //返回渲染好的HTML字符串
        }

        return function() { //返回渲染方法
            args = Array.prototype.slice.call(arguments);
            return func.apply(args.shift(), args);
        }
    };

    myTemplate.version = '0.2.0';

    // Runs myTemplate.js in *noConflict* mode, returning the `myTemplate` variable
    // to its previous owner. Returns a reference to this myTemplate object.
    myTemplate.noConflict = function() {
        root.myTemplate = previousMyTemplate;
        return this;
    };

    return myTemplate;
}));<commit_msg>remove error comments<commit_after>//     myTemplate.js 0.2.0

//     (c) 2014 Guoyao Wu,
//     myTemplate may be freely distributed under the BSD license.
//     For all details and documentation:
//     https://github.com/guoyao/myTemplate

(function(root, factory) {
    // Set up myTemplate appropriately for the environment. Start with AMD.
    if (typeof define === 'function' && define.amd) {
        define(function() {
            return factory(root);
        });
    // Next for Node.js or CommonJS.
    } else if (typeof exports !== 'undefined') {
        module.exports = factory(root);
    // Finally, as a browser global.
    } else {
        root.myTemplate = factory(root);
    }
}(this, function(root) {

    // Save the previous value of the `myTemplate` variable, so that it can be
    // restored later on, if `noConflict` is used.
    var previousMyTemplate = root.myTemplate;

    /**
     * 模板引擎
     * @name    myTemplate
     * @param   {String}  模板字符串
     * @param   {Object}  数据
     * @return  {String, Function}  渲染好的HTML字符串或者渲染方法
     */
    var myTemplate = function template() {
        'use strict';

        var args = Array.prototype.slice.call(arguments),
            tmpl = args.shift().replace(/\r|\n/g, "").replace(/"/g, '\\"'), //转义"号
            funcBody = 'var result = "' + tmpl + '";',
            func;

        funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
            return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时，恢复<%=%>中被转义的"号
        });
        funcBody = funcBody.replace(/<%\s*([^>]*)\s*%>/g, function(match, $1) {
            return '";' + $1.replace(/\\"/g, '"') + 'result += "'; //替换的同时，恢复<%=%>中被转义的"号
        });

        funcBody += " return result;";

        func = new Function(funcBody);
        if (args.length > 0) {
            return func.apply(args.shift(), args); //返回渲染好的HTML字符串
        }

        return function() { //返回渲染方法
            args = Array.prototype.slice.call(arguments);
            return func.apply(args.shift(), args);
        }
    };

    myTemplate.version = '0.2.0';

    // Runs myTemplate.js in *noConflict* mode, returning the `myTemplate` variable
    // to its previous owner. Returns a reference to this myTemplate object.
    myTemplate.noConflict = function() {
        root.myTemplate = previousMyTemplate;
        return this;
    };

    return myTemplate;
}));
<|endoftext|>


<commit_before>$(function () {
    inputChanges();
});

function esc(input) {
    return ('' + input) /* Forces the conversion to string. */
        .replace(/&/g, '&') /* This MUST be the 1st replacement. */
        .replace(/'/g, ''') /* The 4 other predefined entities, required. */
        .replace(/"/g, '"')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        /*
        You may add other replacements here for HTML only
        (but it's not necessary).
        Or for XML, only if the named entities are defined in its DTD.
        */
        ;
}

function unesc(input) {
    return ('' + input)
        .replace(/&/g, '&')
        .replace(/</g, '<')
        .replace(/>/g, '>')
}

Vue.use(VeeValidate);
var dictionary = {
    en: {
        attributes: {
            price: 'Price', checkoutDesc: 'Checkout Description', orderId: 'Order Id',
            serverIpn: 'Server IPN', notifyEmail: 'Send Email Notifications', browserRedirect: 'Browser Redirect',
            payButtonImageUrl: "Pay Button Image Url"
        }
    }
};
VeeValidate.Validator.localize(dictionary);

function getStyles (styles) {
    return document.getElementById(styles).innerHTML.replace(/\s{2}/g, '').trim() + '\n'
}

function getScripts(srvModel) {
    const scripts = []
    if (srvModel.useModal) {
        const modal = document.getElementById('template-modal')
        scripts.push(unesc(modal.innerHTML))
    }
    if (srvModel.buttonType == '1') {
        const priceButtons = document.getElementById('template-price-buttons')
        const priceInput = document.getElementById('template-price-input')
        scripts.push(unesc(priceButtons.innerHTML))
        scripts.push(unesc(priceInput.innerHTML))
    }
    if (srvModel.buttonType == '2') {
        const priceSlider = document.getElementById('template-price-slider')
        const priceInput = document.getElementById('template-price-input')
        scripts.push(unesc(priceSlider.innerHTML))
        scripts.push(unesc(priceInput.innerHTML))
    }
    return scripts
}

function inputChanges(event, buttonSize) {
    if (buttonSize !== null && buttonSize !== undefined) {
        srvModel.buttonSize = buttonSize;
    }

    let width = '209px';
    let height = '57px';
    let widthInput = '3em';
    if (srvModel.buttonSize === 0) {
        width = '146px';
        widthInput = '2em';
        height = '40px';
    } else if (srvModel.buttonSize === 1) {
        width = '168px';
        height = '46px';
    } else if (srvModel.buttonSize === 2) {
        width = '209px';
        height = '57px';
    }
    let actionUrl = 'api/v1/invoices';
    let priceInputName = 'price';
    let app = srvModel.appIdEndpoint? srvModel.apps.find(value => value.id === srvModel.appIdEndpoint ): null;
    let allowCurrencySelection = true;
    let allowDefaultPaymentMethodSelection = true;
    if (app) {
        if (app.appType.toLowerCase() === 'pointofsale') {
            actionUrl = `apps/${app.id}/pos`;
        } else if (app.appType.toLowerCase() === 'crowdfund') {
            actionUrl = `apps/${app.id}/crowdfund`;
        } else {
            actionUrl = 'api/v1/invoices';
            app = null;
        }

        if (actionUrl !== 'api/v1/invoices') {
            priceInputName = 'amount';
            allowCurrencySelection = false;
            allowDefaultPaymentMethodSelection = false;
            srvModel.useModal = false;
        }
    }

    var html =
        // Styles
        getStyles('template-paybutton-styles') + (srvModel.buttonType == '2' ? getStyles('template-slider-styles') : '') +
        // Form
        '<form method="POST"' + (srvModel.useModal ? ' onsubmit="onBTCPayFormSubmit(event);return false"' : '') + ' action="' + esc(srvModel.urlRoot) + actionUrl + '" class="btcpay-form btcpay-form--' + (srvModel.fitButtonInline ? 'inline' : 'block') +'">\n' +
            addInput("storeId", srvModel.storeId);

    if (app) {
        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.serverIpn) html += addInput("notificationUrl", srvModel.serverIpn);
        if (srvModel.browserRedirect) html += addInput("redirectUrl", srvModel.browserRedirect);
        if (srvModel.appChoiceKey) html += addInput("choiceKey", srvModel.appChoiceKey);
    } else {
        if (srvModel.useModal) html += addInput("jsonResponse", true);
        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.checkoutDesc) html += addInput("checkoutDesc", srvModel.checkoutDesc);
        if (srvModel.serverIpn) html += addInput("serverIpn", srvModel.serverIpn);
        if (srvModel.browserRedirect) html += addInput("browserRedirect", srvModel.browserRedirect);
        if (srvModel.notifyEmail) html += addInput("notifyEmail", srvModel.notifyEmail);
        if (srvModel.checkoutQueryString) html += addInput("checkoutQueryString", srvModel.checkoutQueryString);
    }

    // Fixed amount: Add price and currency as hidden inputs
    if (srvModel.buttonType == '0') {
        if (srvModel.price) html += addInput(priceInputName, srvModel.price);
        if (allowCurrencySelection) html += addInput("currency", srvModel.currency);
    }
    // Custom amount
    else if (srvModel.buttonType == '1') {
        html += '
\n
\n';
        html += srvModel.simpleInput ? '' : addPlusMinusButton("-", srvModel.step, srvModel.min, srvModel.max);
        html += addInputPrice(priceInputName, srvModel.price, widthInput, srvModel.min, srvModel.max, srvModel.step);
        html += srvModel.simpleInput ? '' : addPlusMinusButton("+", srvModel.step, srvModel.min, srvModel.max);
        html += '
\n';
        if (allowCurrencySelection) html += addSelectCurrency(srvModel.currency);
        html += '
\n';
    }
    // Slider
    else if (srvModel.buttonType == '2') {
        const step = srvModel.step === 'any' ? 1 : srvModel.step;
        const min = srvModel.min == null ? 1 : parseInt(srvModel.min);
        const max = srvModel.max == null ? null : parseInt(srvModel.max);

        html += '
\n';
        html += addInputPrice(priceInputName, srvModel.price, width, min, max, step, 'handleSliderChange(event);return false');
        if (allowCurrencySelection) html += addSelectCurrency(srvModel.currency);
        html += addSlider(srvModel.price, srvModel.min, srvModel.max, srvModel.step, width);
        html += '
\n';
    }

    if (allowDefaultPaymentMethodSelection && srvModel.defaultPaymentMethod !== "")
    {
        html += addInput("defaultPaymentMethod", srvModel.defaultPaymentMethod)
    }

    html += srvModel.payButtonText
        ? `<button type="submit" class="submit" name="submit" style="min-width:${width};min-height:${height};border-radius:4px;border-style:none;background-color:#0f3b21;" title="Pay with BTCPay Server, a Self-Hosted Bitcoin Payment Processor">${esc(srvModel.payButtonText)}\n` +
            (srvModel.payButtonImageUrl? `<img src="${esc(srvModel.payButtonImageUrl)}" style="height:${parseInt(height.replace('px', ''))}px;display:inline-block;padding:5% 0 5% 5px;vertical-align:middle;">\n` : '') +
          '</button>'
        : `  <input type="image" class="submit" name="submit" src="${esc(srvModel.payButtonImageUrl)}" style="width:${width}" alt="Pay with BTCPay Server, a Self-Hosted Bitcoin Payment Processor">\n`;
    html += '</form>';

    // Scripts
    const scripts = getScripts(srvModel);
    const code = html + (scripts.length ? `\n<script>\n    ${scripts.join('').trim()}\n</script>` : '')

    $("#mainCode").text(code).html();
    const preview = document.getElementById('preview');
    preview.innerHTML = html;
    scripts.forEach(snippet => {
        // script needs to be inserted as node, otherwise it won't get executed
        const script = document.createElement('script')
        script.innerHTML = snippet
        preview.appendChild(script)
    })
    const form = preview.querySelector("form");
    const formData = new FormData(form);
    let url = new URL(form.getAttribute("action"));
    formData.forEach((value, key) => {
        if (key !== "jsonResponse") {
            url.searchParams.append(key, value);
        }
    });
    url = url.href;

    $("#preview-link").attr('href', url);

    $('pre code').each(function (i, block) {
        hljs.highlightBlock(block);
    });

    return html;
}

function addInput(name, value) {
    return `  <input type="hidden" name="${esc(name)}" value="${esc(value)}" />\n`;
}

function addPlusMinusButton(type, step, min, max) {
    step = step === "any" ? 1 : step;
    min = min == null ? 1 : parseInt(min);
    max = max == null ? null : parseInt(max);

    return `      <button class="plus-minus" type="button" onclick="handlePlusMinus(event);return false" data-type="${type}" data-step="${step}" data-min="${min}" data-max="${max}">${type}</button>\n`;
}

function addInputPrice(name, price, widthInput, min = 0, max = 'none', step = 'any', onChange = null) {
    if (!price) price = min
    return `      <input class="btcpay-input-price" type="number" name="${esc(name)}" min="${min}" max="${max}" step="${step}" value="${price}" data-price="${price}" style="width:${widthInput};" oninput="handlePriceInput(event);return false"${onChange ? ` onchange="${onChange}"` : ''} />\n`;
}

function addSlider(price, min, max, step, width) {
    if (!price) price = min
    return `    <input type="range" class="btcpay-input-range" min="${min}" max="${max}" step="${step}" value="${price}" style="width:${width};margin-bottom:15px;" oninput="handleSliderInput(event);return false" />\n`;
}

function addSelectCurrency(currency) {
    // Remove all non-alphabet characters from input string and uppercase it for display
    const safeCurrency = currency.replace(/[^a-z]/gi, '').toUpperCase();
    const defaultCurrencies = ['USD', 'GBP', 'EUR', 'BTC'];
    const options = defaultCurrencies.map(c => `      <option value="${c}"${(c === safeCurrency ? ' selected' : '')}>${c}</option>`);
    // If user provided a currency not in our default currencies list, add it to the top of the options as a selected option
    if (defaultCurrencies.indexOf(safeCurrency) === -1) {
        options.unshift(`      <option value="${safeCurrency}" selected>${safeCurrency}</option>`)
    }

    return `    <select name="currency">\n${options.join('\n')}\n    </select>\n`
}
<commit_msg>Set explicit cursor style property on pay button with custom text (#4107)<commit_after>$(function () {
    inputChanges();
});

function esc(input) {
    return ('' + input) /* Forces the conversion to string. */
        .replace(/&/g, '&') /* This MUST be the 1st replacement. */
        .replace(/'/g, ''') /* The 4 other predefined entities, required. */
        .replace(/"/g, '"')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        /*
        You may add other replacements here for HTML only
        (but it's not necessary).
        Or for XML, only if the named entities are defined in its DTD.
        */
        ;
}

function unesc(input) {
    return ('' + input)
        .replace(/&/g, '&')
        .replace(/</g, '<')
        .replace(/>/g, '>')
}

Vue.use(VeeValidate);
var dictionary = {
    en: {
        attributes: {
            price: 'Price', checkoutDesc: 'Checkout Description', orderId: 'Order Id',
            serverIpn: 'Server IPN', notifyEmail: 'Send Email Notifications', browserRedirect: 'Browser Redirect',
            payButtonImageUrl: "Pay Button Image Url"
        }
    }
};
VeeValidate.Validator.localize(dictionary);

function getStyles (styles) {
    return document.getElementById(styles).innerHTML.replace(/\s{2}/g, '').trim() + '\n'
}

function getScripts(srvModel) {
    const scripts = []
    if (srvModel.useModal) {
        const modal = document.getElementById('template-modal')
        scripts.push(unesc(modal.innerHTML))
    }
    if (srvModel.buttonType == '1') {
        const priceButtons = document.getElementById('template-price-buttons')
        const priceInput = document.getElementById('template-price-input')
        scripts.push(unesc(priceButtons.innerHTML))
        scripts.push(unesc(priceInput.innerHTML))
    }
    if (srvModel.buttonType == '2') {
        const priceSlider = document.getElementById('template-price-slider')
        const priceInput = document.getElementById('template-price-input')
        scripts.push(unesc(priceSlider.innerHTML))
        scripts.push(unesc(priceInput.innerHTML))
    }
    return scripts
}

function inputChanges(event, buttonSize) {
    if (buttonSize !== null && buttonSize !== undefined) {
        srvModel.buttonSize = buttonSize;
    }

    let width = '209px';
    let height = '57px';
    let widthInput = '3em';
    if (srvModel.buttonSize === 0) {
        width = '146px';
        widthInput = '2em';
        height = '40px';
    } else if (srvModel.buttonSize === 1) {
        width = '168px';
        height = '46px';
    } else if (srvModel.buttonSize === 2) {
        width = '209px';
        height = '57px';
    }
    let actionUrl = 'api/v1/invoices';
    let priceInputName = 'price';
    let app = srvModel.appIdEndpoint? srvModel.apps.find(value => value.id === srvModel.appIdEndpoint ): null;
    let allowCurrencySelection = true;
    let allowDefaultPaymentMethodSelection = true;
    if (app) {
        if (app.appType.toLowerCase() === 'pointofsale') {
            actionUrl = `apps/${app.id}/pos`;
        } else if (app.appType.toLowerCase() === 'crowdfund') {
            actionUrl = `apps/${app.id}/crowdfund`;
        } else {
            actionUrl = 'api/v1/invoices';
            app = null;
        }

        if (actionUrl !== 'api/v1/invoices') {
            priceInputName = 'amount';
            allowCurrencySelection = false;
            allowDefaultPaymentMethodSelection = false;
            srvModel.useModal = false;
        }
    }

    var html =
        // Styles
        getStyles('template-paybutton-styles') + (srvModel.buttonType == '2' ? getStyles('template-slider-styles') : '') +
        // Form
        '<form method="POST"' + (srvModel.useModal ? ' onsubmit="onBTCPayFormSubmit(event);return false"' : '') + ' action="' + esc(srvModel.urlRoot) + actionUrl + '" class="btcpay-form btcpay-form--' + (srvModel.fitButtonInline ? 'inline' : 'block') +'">\n' +
            addInput("storeId", srvModel.storeId);

    if (app) {
        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.serverIpn) html += addInput("notificationUrl", srvModel.serverIpn);
        if (srvModel.browserRedirect) html += addInput("redirectUrl", srvModel.browserRedirect);
        if (srvModel.appChoiceKey) html += addInput("choiceKey", srvModel.appChoiceKey);
    } else {
        if (srvModel.useModal) html += addInput("jsonResponse", true);
        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.checkoutDesc) html += addInput("checkoutDesc", srvModel.checkoutDesc);
        if (srvModel.serverIpn) html += addInput("serverIpn", srvModel.serverIpn);
        if (srvModel.browserRedirect) html += addInput("browserRedirect", srvModel.browserRedirect);
        if (srvModel.notifyEmail) html += addInput("notifyEmail", srvModel.notifyEmail);
        if (srvModel.checkoutQueryString) html += addInput("checkoutQueryString", srvModel.checkoutQueryString);
    }

    // Fixed amount: Add price and currency as hidden inputs
    if (srvModel.buttonType == '0') {
        if (srvModel.price) html += addInput(priceInputName, srvModel.price);
        if (allowCurrencySelection) html += addInput("currency", srvModel.currency);
    }
    // Custom amount
    else if (srvModel.buttonType == '1') {
        html += '
\n
\n';
        html += srvModel.simpleInput ? '' : addPlusMinusButton("-", srvModel.step, srvModel.min, srvModel.max);
        html += addInputPrice(priceInputName, srvModel.price, widthInput, srvModel.min, srvModel.max, srvModel.step);
        html += srvModel.simpleInput ? '' : addPlusMinusButton("+", srvModel.step, srvModel.min, srvModel.max);
        html += '
\n';
        if (allowCurrencySelection) html += addSelectCurrency(srvModel.currency);
        html += '
\n';
    }
    // Slider
    else if (srvModel.buttonType == '2') {
        const step = srvModel.step === 'any' ? 1 : srvModel.step;
        const min = srvModel.min == null ? 1 : parseInt(srvModel.min);
        const max = srvModel.max == null ? null : parseInt(srvModel.max);

        html += '
\n';
        html += addInputPrice(priceInputName, srvModel.price, width, min, max, step, 'handleSliderChange(event);return false');
        if (allowCurrencySelection) html += addSelectCurrency(srvModel.currency);
        html += addSlider(srvModel.price, srvModel.min, srvModel.max, srvModel.step, width);
        html += '
\n';
    }

    if (allowDefaultPaymentMethodSelection && srvModel.defaultPaymentMethod !== "")
    {
        html += addInput("defaultPaymentMethod", srvModel.defaultPaymentMethod)
    }

    html += srvModel.payButtonText
        ? `<button type="submit" class="submit" name="submit" style="min-width:${width};min-height:${height};border-radius:4px;border-style:none;background-color:#0f3b21;cursor:pointer;" title="Pay with BTCPay Server, a Self-Hosted Bitcoin Payment Processor">${esc(srvModel.payButtonText)}\n` +
            (srvModel.payButtonImageUrl? `<img src="${esc(srvModel.payButtonImageUrl)}" style="height:${parseInt(height.replace('px', ''))}px;display:inline-block;padding:5% 0 5% 5px;vertical-align:middle;">\n` : '') +
          '</button>'
        : `  <input type="image" class="submit" name="submit" src="${esc(srvModel.payButtonImageUrl)}" style="width:${width}" alt="Pay with BTCPay Server, a Self-Hosted Bitcoin Payment Processor">\n`;
    html += '</form>';

    // Scripts
    const scripts = getScripts(srvModel);
    const code = html + (scripts.length ? `\n<script>\n    ${scripts.join('').trim()}\n</script>` : '')

    $("#mainCode").text(code).html();
    const preview = document.getElementById('preview');
    preview.innerHTML = html;
    scripts.forEach(snippet => {
        // script needs to be inserted as node, otherwise it won't get executed
        const script = document.createElement('script')
        script.innerHTML = snippet
        preview.appendChild(script)
    })
    const form = preview.querySelector("form");
    const formData = new FormData(form);
    let url = new URL(form.getAttribute("action"));
    formData.forEach((value, key) => {
        if (key !== "jsonResponse") {
            url.searchParams.append(key, value);
        }
    });
    url = url.href;

    $("#preview-link").attr('href', url);

    $('pre code').each(function (i, block) {
        hljs.highlightBlock(block);
    });

    return html;
}

function addInput(name, value) {
    return `  <input type="hidden" name="${esc(name)}" value="${esc(value)}" />\n`;
}

function addPlusMinusButton(type, step, min, max) {
    step = step === "any" ? 1 : step;
    min = min == null ? 1 : parseInt(min);
    max = max == null ? null : parseInt(max);

    return `      <button class="plus-minus" type="button" onclick="handlePlusMinus(event);return false" data-type="${type}" data-step="${step}" data-min="${min}" data-max="${max}">${type}</button>\n`;
}

function addInputPrice(name, price, widthInput, min = 0, max = 'none', step = 'any', onChange = null) {
    if (!price) price = min
    return `      <input class="btcpay-input-price" type="number" name="${esc(name)}" min="${min}" max="${max}" step="${step}" value="${price}" data-price="${price}" style="width:${widthInput};" oninput="handlePriceInput(event);return false"${onChange ? ` onchange="${onChange}"` : ''} />\n`;
}

function addSlider(price, min, max, step, width) {
    if (!price) price = min
    return `    <input type="range" class="btcpay-input-range" min="${min}" max="${max}" step="${step}" value="${price}" style="width:${width};margin-bottom:15px;" oninput="handleSliderInput(event);return false" />\n`;
}

function addSelectCurrency(currency) {
    // Remove all non-alphabet characters from input string and uppercase it for display
    const safeCurrency = currency.replace(/[^a-z]/gi, '').toUpperCase();
    const defaultCurrencies = ['USD', 'GBP', 'EUR', 'BTC'];
    const options = defaultCurrencies.map(c => `      <option value="${c}"${(c === safeCurrency ? ' selected' : '')}>${c}</option>`);
    // If user provided a currency not in our default currencies list, add it to the top of the options as a selected option
    if (defaultCurrencies.indexOf(safeCurrency) === -1) {
        options.unshift(`      <option value="${safeCurrency}" selected>${safeCurrency}</option>`)
    }

    return `    <select name="currency">\n${options.join('\n')}\n    </select>\n`
}
<|endoftext|>


<commit_before>$(function () {
    inputChanges();

    // Clipboard Copy
    new Clipboard('#copyCode', {
        text: function (trigger) {
            $(".copyLabelPopup").show().delay(1000).fadeOut(500);
            return inputChanges();
        }
    });
});

function esc(input) {
    return ('' + input) /* Forces the conversion to string. */
        .replace(/&/g, '&') /* This MUST be the 1st replacement. */
        .replace(/'/g, ''') /* The 4 other predefined entities, required. */
        .replace(/"/g, '"')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        /*
        You may add other replacements here for HTML only
        (but it's not necessary).
        Or for XML, only if the named entities are defined in its DTD.
        */
        ;
}

Vue.use(VeeValidate);
var dictionary = {
    en: {
        attributes: {
            price: 'Price', checkoutDesc: 'Checkout Description', orderId: 'Order Id',
            serverIpn: 'Server IPN', notifyEmail: 'Send Email Notifications', browserRedirect: 'Browser Redirect',
            payButtonImageUrl: "Pay Button Image Url"
        }
    }
};
VeeValidate.Validator.localize(dictionary);

function getStyles (styles) {
    return document.getElementById(styles).innerHTML.trim().replace(/\s{2}/g, '') + '\n'
}

function getScripts(srvModel) {
    return ""+
        "";
}

function inputChanges(event, buttonSize) {
    if (buttonSize !== null && buttonSize !== undefined) {
        srvModel.buttonSize = buttonSize;
    }

    var isFixedAmount = srvModel.buttonType == 0
    var isCustomAmount = srvModel.buttonType == 1
    var isSlider = srvModel.buttonType == 2

    var width = "209px";
    var height = "57px";
    var widthInput = "3em";
    if (srvModel.buttonSize === 0) {
        width = "146px";
        widthInput = "2em";
        height = "40px";
    } else if (srvModel.buttonSize === 1) {
        width = "168px";
        height = "46px";
    } else if (srvModel.buttonSize === 2) {
        width = "209px";
        height = "57px";
    }
    var actionUrl = "api/v1/invoices";
    var priceInputName = "price";
    var app = srvModel.appIdEndpoint? srvModel.apps.find(value => value.id === srvModel.appIdEndpoint ): null;
    var allowCurrencySelection = true;
    if (app) {

        if (app.appType.toLowerCase() == "pointofsale") {
            actionUrl = "apps/" + app.id + "/pos";
        } else if (app.appType.toLowerCase() == "crowdfund") {
            actionUrl = "apps/" + app.id + "/crowdfund";
        } else {
            actionUrl = "api/v1/invoices";
            app = null;
        }

        if (actionUrl != "api/v1/invoices") {
            priceInputName = "amount";
            allowCurrencySelection = false;
            srvModel.useModal = false;
        }
    }

    var html =
        //Scripts
        (srvModel.useModal? getScripts(srvModel) :"") +
        // Styles
        getStyles('template-paybutton-styles') + (isSlider ? getStyles('template-slider-styles') : '') +
        // Form
        '<form method="POST" '+ ( srvModel.useModal? ' onsubmit="onBTCPayFormSubmit(event);return false" ' : '' )+' action="' + esc(srvModel.urlRoot) + actionUrl + '" class="btcpay-form btcpay-form--' + (srvModel.fitButtonInline ? 'inline' : 'block') +'">\n' +
            addInput("storeId", srvModel.storeId);

    if(app){
        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.serverIpn) html += addInput("notificationUrl", srvModel.serverIpn);
        if (srvModel.browserRedirect) html += addInput("redirectUrl", srvModel.browserRedirect);
        if (srvModel.appChoiceKey) html += addInput("choiceKey", srvModel.appChoiceKey);

    }else{
        if (srvModel.useModal) html += addInput("jsonResponse", true);

        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.checkoutDesc) html += addInput("checkoutDesc", srvModel.checkoutDesc);

        if (srvModel.serverIpn) html += addInput("serverIpn", srvModel.serverIpn);

        if (srvModel.browserRedirect) html += addInput("browserRedirect", srvModel.browserRedirect);

        if (srvModel.notifyEmail) html += addInput("notifyEmail", srvModel.notifyEmail);

        if (srvModel.checkoutQueryString) html += addInput("checkoutQueryString", srvModel.checkoutQueryString);
    }

    // Fixed amount: Add price and currency as hidden inputs
    if (isFixedAmount) {
        if (srvModel.price !== '')
            html += addInput(priceInputName, srvModel.price);
        if(allowCurrencySelection){
            html += addInput("currency", srvModel.currency);
        }
    }
    // Custom amount
    else if (isCustomAmount) {
        html += '
\n
\n';
        html += srvModel.simpleInput ? '' : addPlusMinusButton("-", srvModel.step, srvModel.min, srvModel.max);
        html += '  ' + addInputPrice(priceInputName, srvModel.price, widthInput, "",   "number", srvModel.min, srvModel.max, srvModel.step);
        html += srvModel.simpleInput ? '' : addPlusMinusButton("+", srvModel.step, srvModel.min, srvModel.max);
        html += '
\n';
        if(allowCurrencySelection) {
            html += addSelectCurrency(srvModel.currency);
        }
        html += '
\n';
    }
    // Slider
    else if (isSlider) {
        var step = srvModel.step =="any"? 1: srvModel.step;
        var min = srvModel.min == null? 1: parseInt(srvModel.min);
        var max = srvModel.max == null? 1: parseInt(srvModel.max);
        var onChange = "var el=document.querySelector(\'#btcpay-input-price\'); var price = parseInt(el.value);  if(price< "+min+") { el.value = "+min+"} else if(price> "+max+") { el.value = "+max+"} document.querySelector(\'#btcpay-input-range\').value = el.value"

        html += '
\n';
        html += addInputPrice(priceInputName, srvModel.price, width, 'onchange= \"'+onChange+'\"');
        if(allowCurrencySelection) {
            html += addSelectCurrency(srvModel.currency);
        }
        html += addSlider(srvModel.price, srvModel.min, srvModel.max, srvModel.step, width);
        html += '
\n';
    }

    if(!srvModel.payButtonText){
        html += '  <input type="image" class="submit" name="submit" src="' + esc(srvModel.payButtonImageUrl) + '" style="width:' + width + '" alt="Pay with BtcPay, Self-Hosted Bitcoin Payment Processor">\n';
    }else{
        var numheight = parseInt(height.replace("px", ""));
        html+= '<button type="submit" class="submit" name="submit" style="min-width:' + width + '; min-height:' + height + '; border-radius: 4px;border-style: none;background-color: #0f3b21;" alt="Pay with BtcPay, Self-Hosted Bitcoin Payment Processor">'+esc(srvModel.payButtonText)+'\n' +
            (srvModel.payButtonImageUrl? '\n' : '')+
            '</button>'
    }
    html += '</form>';

    $("#mainCode").text(html).html();
    $("#preview").html(html);
    var form = document.querySelector("#preview form");
    var url =  new URL(form.getAttribute("action"));
    var formData =   new FormData(form);
    formData.forEach((value, key) => {
        if(key !== "jsonResponse"){
            url.searchParams.append(key, value);
        }
    });
    url = url.href;

    $("#preview-link").empty().append($('').text(url).attr('href', url));

    $('pre code').each(function (i, block) {
        hljs.highlightBlock(block);
    });

    return html;
}

function addInput(name, value) {
    return '  <input type="hidden" name="' + esc(name) + '" value="' + esc(value) + '" />\n';
}

function addPlusMinusButton(type, step, min, max) {
    step = step =="any"? 1: step;
    min = min == null? 1: parseInt(min);
    max = max == null? 1: parseInt(max);
    var onChange = "event.preventDefault(); var el=document.querySelector(\'#btcpay-input-price\'); var price = parseInt(el.value);"
    if(type == "-"){
        onChange += " if((price - "+step+" )< "+min+") { el.value = "+min+"} else {el.value = parseInt(el.value) - "+step + " }";
    } else if(type == "+"){
        onChange += " if((price + "+step+" )> "+max+") { el.value = "+max+"} else {el.value = parseInt(el.value) + "+step + " }";
    }

    return '      <button class="plus-minus" onclick="'+onChange+'">' + type + '</button>\n';
   }

function addInputPrice(name, price, widthInput, customFn, type, min, max, step) {
    return '    <input id="btcpay-input-price" name="'+name+'" type="' + (type || "text") + '" min="' + (min || 0) + '" max="' + (max || "none") + '" step="' + (step || "any") + '" value="' + price + '" style="width: ' + widthInput + ';" oninput="event.preventDefault();isNaN(event.target.value)? document.querySelector(\'#btcpay-input-price\').value = ' + price + ' : event.target.value; if (this.value < '+min+') {this.value = '+min+'; } else if(this.value > '+max+'){  this.value = '+max+';}" ' + (customFn || '') + ' />\n';
}

function addSelectCurrency(currency) {
    return '    <select name="currency">\n' +
        ['USD', 'GBP', 'EUR', 'BTC'].map(c => '      <option value="' + c + '"' + (c === currency ? ' selected' : '') + '>' + c + '</option>').join('\n') + '\n' +
    '    </select>\n'
}

function addSlider(price, min, max, step, width) {
    return '    <input class="btcpay-input-range" id="btcpay-input-range" value="' + price + '" type="range" min="' + min + '" max="' + max + '" step="' + step + '" style="width:' + width + ';margin-bottom:15px;" oninput="document.querySelector(\'#btcpay-input-price\').value = document.querySelector(\'#btcpay-input-range\').value" />\n';
}
<commit_msg>Fix paybutton like when no amount set<commit_after>$(function () {
    inputChanges();

    // Clipboard Copy
    new Clipboard('#copyCode', {
        text: function (trigger) {
            $(".copyLabelPopup").show().delay(1000).fadeOut(500);
            return inputChanges();
        }
    });
});

function esc(input) {
    return ('' + input) /* Forces the conversion to string. */
        .replace(/&/g, '&') /* This MUST be the 1st replacement. */
        .replace(/'/g, ''') /* The 4 other predefined entities, required. */
        .replace(/"/g, '"')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        /*
        You may add other replacements here for HTML only
        (but it's not necessary).
        Or for XML, only if the named entities are defined in its DTD.
        */
        ;
}

Vue.use(VeeValidate);
var dictionary = {
    en: {
        attributes: {
            price: 'Price', checkoutDesc: 'Checkout Description', orderId: 'Order Id',
            serverIpn: 'Server IPN', notifyEmail: 'Send Email Notifications', browserRedirect: 'Browser Redirect',
            payButtonImageUrl: "Pay Button Image Url"
        }
    }
};
VeeValidate.Validator.localize(dictionary);

function getStyles (styles) {
    return document.getElementById(styles).innerHTML.trim().replace(/\s{2}/g, '') + '\n'
}

function getScripts(srvModel) {
    return ""+
        "";
}

function inputChanges(event, buttonSize) {
    if (buttonSize !== null && buttonSize !== undefined) {
        srvModel.buttonSize = buttonSize;
    }

    var isFixedAmount = srvModel.buttonType == 0
    var isCustomAmount = srvModel.buttonType == 1
    var isSlider = srvModel.buttonType == 2

    var width = "209px";
    var height = "57px";
    var widthInput = "3em";
    if (srvModel.buttonSize === 0) {
        width = "146px";
        widthInput = "2em";
        height = "40px";
    } else if (srvModel.buttonSize === 1) {
        width = "168px";
        height = "46px";
    } else if (srvModel.buttonSize === 2) {
        width = "209px";
        height = "57px";
    }
    var actionUrl = "api/v1/invoices";
    var priceInputName = "price";
    var app = srvModel.appIdEndpoint? srvModel.apps.find(value => value.id === srvModel.appIdEndpoint ): null;
    var allowCurrencySelection = true;
    if (app) {

        if (app.appType.toLowerCase() == "pointofsale") {
            actionUrl = "apps/" + app.id + "/pos";
        } else if (app.appType.toLowerCase() == "crowdfund") {
            actionUrl = "apps/" + app.id + "/crowdfund";
        } else {
            actionUrl = "api/v1/invoices";
            app = null;
        }

        if (actionUrl != "api/v1/invoices") {
            priceInputName = "amount";
            allowCurrencySelection = false;
            srvModel.useModal = false;
        }
    }

    var html =
        //Scripts
        (srvModel.useModal? getScripts(srvModel) :"") +
        // Styles
        getStyles('template-paybutton-styles') + (isSlider ? getStyles('template-slider-styles') : '') +
        // Form
        '<form method="POST" '+ ( srvModel.useModal? ' onsubmit="onBTCPayFormSubmit(event);return false" ' : '' )+' action="' + esc(srvModel.urlRoot) + actionUrl + '" class="btcpay-form btcpay-form--' + (srvModel.fitButtonInline ? 'inline' : 'block') +'">\n' +
            addInput("storeId", srvModel.storeId);

    if(app){
        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.serverIpn) html += addInput("notificationUrl", srvModel.serverIpn);
        if (srvModel.browserRedirect) html += addInput("redirectUrl", srvModel.browserRedirect);
        if (srvModel.appChoiceKey) html += addInput("choiceKey", srvModel.appChoiceKey);

    }else{
        if (srvModel.useModal) html += addInput("jsonResponse", true);

        if (srvModel.orderId) html += addInput("orderId", srvModel.orderId);
        if (srvModel.checkoutDesc) html += addInput("checkoutDesc", srvModel.checkoutDesc);

        if (srvModel.serverIpn) html += addInput("serverIpn", srvModel.serverIpn);

        if (srvModel.browserRedirect) html += addInput("browserRedirect", srvModel.browserRedirect);

        if (srvModel.notifyEmail) html += addInput("notifyEmail", srvModel.notifyEmail);

        if (srvModel.checkoutQueryString) html += addInput("checkoutQueryString", srvModel.checkoutQueryString);
    }

    // Fixed amount: Add price and currency as hidden inputs
    if (isFixedAmount) {
        if (srvModel.price)
            html += addInput(priceInputName, srvModel.price);
        if(allowCurrencySelection){
            html += addInput("currency", srvModel.currency);
        }
    }
    // Custom amount
    else if (isCustomAmount) {
        html += '
\n
\n';
        html += srvModel.simpleInput ? '' : addPlusMinusButton("-", srvModel.step, srvModel.min, srvModel.max);
        if (srvModel.price)
            html += '  ' + addInputPrice(priceInputName, srvModel.price, widthInput, "",   "number", srvModel.min, srvModel.max, srvModel.step);
        html += srvModel.simpleInput ? '' : addPlusMinusButton("+", srvModel.step, srvModel.min, srvModel.max);
        html += '
\n';
        if(allowCurrencySelection) {
            html += addSelectCurrency(srvModel.currency);
        }
        html += '
\n';
    }
    // Slider
    else if (isSlider) {
        var step = srvModel.step =="any"? 1: srvModel.step;
        var min = srvModel.min == null? 1: parseInt(srvModel.min);
        var max = srvModel.max == null? 1: parseInt(srvModel.max);
        var onChange = "var el=document.querySelector(\'#btcpay-input-price\'); var price = parseInt(el.value);  if(price< "+min+") { el.value = "+min+"} else if(price> "+max+") { el.value = "+max+"} document.querySelector(\'#btcpay-input-range\').value = el.value"

        html += '
\n';
        html += addInputPrice(priceInputName, srvModel.price, width, 'onchange= \"'+onChange+'\"');
        if(allowCurrencySelection) {
            html += addSelectCurrency(srvModel.currency);
        }
        html += addSlider(srvModel.price, srvModel.min, srvModel.max, srvModel.step, width);
        html += '
\n';
    }

    if(!srvModel.payButtonText){
        html += '  <input type="image" class="submit" name="submit" src="' + esc(srvModel.payButtonImageUrl) + '" style="width:' + width + '" alt="Pay with BtcPay, Self-Hosted Bitcoin Payment Processor">\n';
    }else{
        var numheight = parseInt(height.replace("px", ""));
        html+= '<button type="submit" class="submit" name="submit" style="min-width:' + width + '; min-height:' + height + '; border-radius: 4px;border-style: none;background-color: #0f3b21;" alt="Pay with BtcPay, Self-Hosted Bitcoin Payment Processor">'+esc(srvModel.payButtonText)+'\n' +
            (srvModel.payButtonImageUrl? '\n' : '')+
            '</button>'
    }
    html += '</form>';

    $("#mainCode").text(html).html();
    $("#preview").html(html);
    var form = document.querySelector("#preview form");
    var url =  new URL(form.getAttribute("action"));
    var formData =   new FormData(form);
    formData.forEach((value, key) => {
        if (key !== "jsonResponse") {
            url.searchParams.append(key, value);
        }
    });
    url = url.href;

    $("#preview-link").empty().append($('').text(url).attr('href', url));

    $('pre code').each(function (i, block) {
        hljs.highlightBlock(block);
    });

    return html;
}

function addInput(name, value) {
    return '  <input type="hidden" name="' + esc(name) + '" value="' + esc(value) + '" />\n';
}

function addPlusMinusButton(type, step, min, max) {
    step = step =="any"? 1: step;
    min = min == null? 1: parseInt(min);
    max = max == null? 1: parseInt(max);
    var onChange = "event.preventDefault(); var el=document.querySelector(\'#btcpay-input-price\'); var price = parseInt(el.value);"
    if(type == "-"){
        onChange += " if((price - "+step+" )< "+min+") { el.value = "+min+"} else {el.value = parseInt(el.value) - "+step + " }";
    } else if(type == "+"){
        onChange += " if((price + "+step+" )> "+max+") { el.value = "+max+"} else {el.value = parseInt(el.value) + "+step + " }";
    }

    return '      <button class="plus-minus" onclick="'+onChange+'">' + type + '</button>\n';
   }

function addInputPrice(name, price, widthInput, customFn, type, min, max, step) {
    return '    <input id="btcpay-input-price" name="'+name+'" type="' + (type || "text") + '" min="' + (min || 0) + '" max="' + (max || "none") + '" step="' + (step || "any") + '" value="' + price + '" style="width: ' + widthInput + ';" oninput="event.preventDefault();isNaN(event.target.value)? document.querySelector(\'#btcpay-input-price\').value = ' + price + ' : event.target.value; if (this.value < '+min+') {this.value = '+min+'; } else if(this.value > '+max+'){  this.value = '+max+';}" ' + (customFn || '') + ' />\n';
}

function addSelectCurrency(currency) {
    return '    <select name="currency">\n' +
        ['USD', 'GBP', 'EUR', 'BTC'].map(c => '      <option value="' + c + '"' + (c === currency ? ' selected' : '') + '>' + c + '</option>').join('\n') + '\n' +
    '    </select>\n'
}

function addSlider(price, min, max, step, width) {
    return '    <input class="btcpay-input-range" id="btcpay-input-range" value="' + price + '" type="range" min="' + min + '" max="' + max + '" step="' + step + '" style="width:' + width + ';margin-bottom:15px;" oninput="document.querySelector(\'#btcpay-input-price\').value = document.querySelector(\'#btcpay-input-range\').value" />\n';
}
<|endoftext|>


<commit_before>const path = require('path')
const fetch = require('node-fetch')
const isURL = require('is-url')

exports.defaultOptions = {
    workerPath: path.join(__dirname, 'worker.js'),
    langPath: 'http://cdn.rawgit.com/naptha/tessdata/gh-pages/3.02/',
}

const fork = require('child_process').fork;
const fs = require('fs')

exports.spawnWorker = function spawnWorker(instance, workerOptions){
    var cp = fork(workerOptions.workerPath);
    cp.on('message', function(packet){
        instance._recv(packet)
    })
    return cp;
}

exports.terminateWorker = function(instance){
    instance.worker.kill()
}

exports.sendPacket = function sendPacket(instance, packet){
    loadImage(packet.payload.image, function(img){
        packet.payload.image = img
        instance.worker.send(packet)
    })
}

function loadImage(image, cb){

    if(isURL(image) {
        fetch(image).then(function (resp) {
            return resp.buffer();
        }).then(function (buffer) {
            return loadImage(buffer, cb);
        }).catch(function (err) {
            return console.error(err);
        });
    })

    if(typeof image === 'string'){
        fs.readFile(image, function(err, buffer){
            if (err) throw err;
            loadImage(buffer, cb)
        })
        return
    }else if(image instanceof Buffer){
        var fileType = require('file-type');
        var mime = fileType(image).mime

        if(mime === 'image/png'){
            var PNGReader = require('png.js');
            var reader = new PNGReader(image);
            reader.parse(function(err, png){
                if (err) throw err;

                var image = {
                    width: png.getWidth(),
                    height: png.getHeight()
                }
                image.data = new Uint8Array(image.width * image.height * 4)
                for(var j = 0; j < image.height; j++){
                    for(var i = 0; i < image.width; i++){
                        var offset = 4 * (i + j * image.width),
                            pix = png.getPixel(i, j);

                        image.data[offset] = pix[0]
                        image.data[offset + 1] = pix[1]
                        image.data[offset + 2] = pix[2]
                        image.data[offset + 3] = pix[3];
                    }
                }
                // console.log(image)
                loadImage(image, cb)
            });
            return
        }else if(mime === 'image/jpeg'){
            var jpeg = require('jpeg-js');
            loadImage(jpeg.decode(image), cb)
            return
        }

        // TODO: support for TIFF, NetPBM, BMP, etc.
    }

    // node uses json.stringify for ipc which means we need to turn
    // fancy arrays into raw arrays
    if(image && image.data && image.data.length && !Array.isArray(image.data)){
        image.data = Array.from(image.data)
        return loadImage(image, cb)
    }
    cb(image)
}<commit_msg>syntax error (we really should add tests)<commit_after>const path = require('path')
const fetch = require('node-fetch')
const isURL = require('is-url')

exports.defaultOptions = {
    workerPath: path.join(__dirname, 'worker.js'),
    langPath: 'http://cdn.rawgit.com/naptha/tessdata/gh-pages/3.02/',
}

const fork = require('child_process').fork;
const fs = require('fs')

exports.spawnWorker = function spawnWorker(instance, workerOptions){
    var cp = fork(workerOptions.workerPath);
    cp.on('message', function(packet){
        instance._recv(packet)
    })
    return cp;
}

exports.terminateWorker = function(instance){
    instance.worker.kill()
}

exports.sendPacket = function sendPacket(instance, packet){
    loadImage(packet.payload.image, function(img){
        packet.payload.image = img
        instance.worker.send(packet)
    })
}

function loadImage(image, cb){

    if(isURL(image)) {
        fetch(image).then(function (resp) {
            return resp.buffer();
        }).then(function (buffer) {
            return loadImage(buffer, cb);
        }).catch(function (err) {
            return console.error(err);
        });
    })

    if(typeof image === 'string'){
        fs.readFile(image, function(err, buffer){
            if (err) throw err;
            loadImage(buffer, cb)
        })
        return
    }else if(image instanceof Buffer){
        var fileType = require('file-type');
        var mime = fileType(image).mime

        if(mime === 'image/png'){
            var PNGReader = require('png.js');
            var reader = new PNGReader(image);
            reader.parse(function(err, png){
                if (err) throw err;

                var image = {
                    width: png.getWidth(),
                    height: png.getHeight()
                }
                image.data = new Uint8Array(image.width * image.height * 4)
                for(var j = 0; j < image.height; j++){
                    for(var i = 0; i < image.width; i++){
                        var offset = 4 * (i + j * image.width),
                            pix = png.getPixel(i, j);

                        image.data[offset] = pix[0]
                        image.data[offset + 1] = pix[1]
                        image.data[offset + 2] = pix[2]
                        image.data[offset + 3] = pix[3];
                    }
                }
                // console.log(image)
                loadImage(image, cb)
            });
            return
        }else if(mime === 'image/jpeg'){
            var jpeg = require('jpeg-js');
            loadImage(jpeg.decode(image), cb)
            return
        }

        // TODO: support for TIFF, NetPBM, BMP, etc.
    }

    // node uses json.stringify for ipc which means we need to turn
    // fancy arrays into raw arrays
    if(image && image.data && image.data.length && !Array.isArray(image.data)){
        image.data = Array.from(image.data)
        return loadImage(image, cb)
    }
    cb(image)
}<|endoftext|>


<commit_before>var squel = require('squel');

function Query(sequelize, Promise) {
    this.sequelize = sequelize;
    this.Promise = Promise;
    this.selectQuery = squel.select();
    this.countQuery = squel.select().field('0');
}

Query.prototype.distinct = function () {
    this.selectQuery.distinct.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.field = function () {
    this.selectQuery.field.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.fields = function () {
    this.selectQuery.fields.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.from = function () {
    this.selectQuery.from.apply(this.selectQuery, arguments);
    this.countQuery.from.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.join = function () {
    this.selectQuery.join.apply(this.selectQuery, arguments);
    this.countQuery.join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.left_join = function () {
    this.selectQuery.left_join.apply(this.selectQuery, arguments);
    this.countQuery.left_join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.right_join = function () {
    this.selectQuery.right_join.apply(this.selectQuery, arguments);
    this.countQuery.right_join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.outer_join = function () {
    this.selectQuery.outer_join.apply(this.selectQuery, arguments);
    this.countQuery.outer_join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.where = function () {
    this.selectQuery.where.apply(this.selectQuery, arguments);
    this.countQuery.where.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.order = function () {
    this.selectQuery.order.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.group = function () {
    this.selectQuery.group.apply(this.selectQuery, arguments);
    this.countQuery.group.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.limit = function () {
    this.selectQuery.limit.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.offset = function () {
    this.selectQuery.offset.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.top = function () {
    this.selectQuery.top.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.join = function () {
    this.selectQuery.join.apply(this.selectQuery, arguments);
    this.countQuery.join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.exec = function () {
    var Promise = this.Promise,
        pageSize = this.pageSize,
        page = this.page;

    return Promise.all([
        this.list(),
        this.count()
    ]).spread(function (result, count) {
        return Promise.resolve({
            list : result,
            count : count,
            page : parseInt(page, 10),
            pages : Math.ceil(count / pageSize)
        });
    });
};

Query.prototype.page = function (page, size) {
    this.pageSize = size;
    this.page = page;
    this.offset((page - 1) * size).limit(size);
    return this;
};

Query.prototype.list = function () {
    var select = this.selectQuery.toString(),
        Promise = this.Promise;

    return this.sequelize.query(select).then(function (selectResult) {
        return Promise.resolve(selectResult);
    });
};

Query.prototype.single = function () {
    var select = this.selectQuery.limit(1).toString(),
        Promise = this.Promise;
    return this.sequelize.query(select).then(function (result) {
        return Promise.resolve(result[0]);
    });
};

Query.prototype.count = function () {
    var query = 'SELECT COUNT(*) as count FROM (' + this.countQuery.toString() + ') c',
        Promise = this.Promise;

    return this.sequelize.query(query).then(function (countResult) {
        return Promise.resolve(countResult[0].count);
    });
};

module.exports = Query;<commit_msg>Mantendo compatibilidade com o Sequelize 2.0.5<commit_after>var squel = require('squel');

function Query(sequelize, Promise) {
    this.sequelize = sequelize;
    this.Promise = Promise;
    this.selectQuery = squel.select();
    this.countQuery = squel.select().field('0');
}

Query.prototype.distinct = function () {
    this.selectQuery.distinct.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.field = function () {
    this.selectQuery.field.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.fields = function () {
    this.selectQuery.fields.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.from = function () {
    this.selectQuery.from.apply(this.selectQuery, arguments);
    this.countQuery.from.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.join = function () {
    this.selectQuery.join.apply(this.selectQuery, arguments);
    this.countQuery.join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.left_join = function () {
    this.selectQuery.left_join.apply(this.selectQuery, arguments);
    this.countQuery.left_join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.right_join = function () {
    this.selectQuery.right_join.apply(this.selectQuery, arguments);
    this.countQuery.right_join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.outer_join = function () {
    this.selectQuery.outer_join.apply(this.selectQuery, arguments);
    this.countQuery.outer_join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.where = function () {
    this.selectQuery.where.apply(this.selectQuery, arguments);
    this.countQuery.where.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.order = function () {
    this.selectQuery.order.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.group = function () {
    this.selectQuery.group.apply(this.selectQuery, arguments);
    this.countQuery.group.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.limit = function () {
    this.selectQuery.limit.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.offset = function () {
    this.selectQuery.offset.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.top = function () {
    this.selectQuery.top.apply(this.selectQuery, arguments);
    return this;
};

Query.prototype.join = function () {
    this.selectQuery.join.apply(this.selectQuery, arguments);
    this.countQuery.join.apply(this.countQuery, arguments);
    return this;
};

Query.prototype.exec = function () {
    var Promise = this.Promise,
        pageSize = this.pageSize,
        page = this.page;

    return Promise.all([
        this.list(),
        this.count()
    ]).spread(function (result, count) {
        return Promise.resolve({
            list : result,
            count : count,
            page : parseInt(page, 10),
            pages : Math.ceil(count / pageSize)
        });
    });
};

Query.prototype.page = function (page, size) {
    this.pageSize = size;
    this.page = page;
    this.offset((page - 1) * size).limit(size);
    return this;
};

Query.prototype.list = function () {
    var select = this.selectQuery.toString(),
        Promise = this.Promise;

    return this.sequelize.query(select).spread(function (selectResult) {
        return Promise.resolve(selectResult);
    });
};

Query.prototype.single = function () {
    var select = this.selectQuery.limit(1).toString(),
        Promise = this.Promise;
    return this.sequelize.query(select).spread(function (result) {
        return Promise.resolve(result[0]);
    });
};

Query.prototype.count = function () {
    var query = 'SELECT COUNT(*) as count FROM (' + this.countQuery.toString() + ') c',
        Promise = this.Promise;

    return this.sequelize.query(query).spread(function (countResult) {
        return Promise.resolve(countResult[0].count);
    });
};

module.exports = Query;<|endoftext|>


<commit_before>const path = require('path');
const yosay = require('yosay');
const _ = require('lodash');
const Base = require('../base');

module.exports = class Generator extends Base {
  constructor() {
    super(...arguments);

    this.option('no-message', {
      desc: 'Skips the welcome message',
      type: Boolean,
    });

    this.option('markups', {
      desc: 'Which markup compiler to use in page',
      type: String
    });

    this.option('styles', {
      desc: 'Which style compiler to use in page',
      type: String
    });
  }

  initializing() {
    this.data = {
      name: '',
      markups: this.options.markups,
      styles: this.options.styles,
      yorc: this.config.getAll(),
      site: this.fs.readJSON(this.destinationPath('config.json'), {}),
    };
  }

  prompting() {
    let done = this.async();

    if (!this.options['no-message']) {
      this.log(yosay('Let\'s make a new page.'));
    }

    const prompts = [{
      type: 'checkbox',
      name: 'markups',
      message: 'Page markup type:',
      choices: [{
        name: 'html',
        value: 'HTML',
      }, {
        name: 'jade',
        value: 'Jade',
      }, {
        name: 'nunjucks',
        value: 'Nunjucks',
      }],
      when: !this.data.markups || ['html', 'jade', 'nunjucks'].indexOf(this.data.markups) === -1,
    }, {
      type: 'checkbox',
      name: 'styles',
      message: 'Page style type:',
      choices: [{
        name: 'css',
        value: 'CSS',
      }, {
        name: 'sass',
        value: 'SASS',
      }, {
        name: 'scss',
        value: 'SCSS',
      }, {
        name: 'less',
        value: 'Less',
      }],
      when: !this.data.styles || ['css', 'sass', 'scss', 'less'].indexOf(this.data.styles) === -1,
    }];

    this.prompt(prompts, (answers) => {
      _.assign(this.data, answers);

      done();
    });
  }

  writing() {
    let out = path.join(this.data.site.src || 'src', this.data.name);
    switch (this.data.markups) {
      case 'jade':
        this._copyDirectory('jade', out);
        break;
      case 'nunjucks':
        this._copyDirectory('nunjucks', out);
        break;
      default:
        this._copyDirectory('html', out);
    }
    switch (this.data.styles) {
      case 'sass':
        this._copyDirectory('sass', out);
        break;
      case 'scss':
        this._copyDirectory('scss', out);
        break;
      case 'less':
        this._copyDirectory('less', out);
        break;
      default:
        this._copyDirectory('css', out);
    }
  }
};
<commit_msg>provide option for setting path of page generator output<commit_after>const path = require('path');
const yosay = require('yosay');
const _ = require('lodash');
const Base = require('../base');

module.exports = class Generator extends Base {
  constructor() {
    super(...arguments);

    this.option('no-message', {
      desc: 'Skips the welcome message',
      type: Boolean,
    });

    this.option('path', {
      desc: 'Path to location of page files',
      type: String
    });

    this.option('markups', {
      desc: 'Which markup compiler to use in page',
      type: String
    });

    this.option('styles', {
      desc: 'Which style compiler to use in page',
      type: String
    });
  }

  initializing() {
    this.data = {
      path: this.options.path,
      markups: this.options.markups,
      styles: this.options.styles,
      yorc: this.config.getAll(),
      site: this.fs.readJSON(this.destinationPath('config.json'), {}),
    };
  }

  prompting() {
    let done = this.async();

    if (!this.options['no-message']) {
      this.log(yosay('Let\'s make a new page.'));
    }

    const prompts = [{
      type: 'input',
      name: 'path',
      message: 'Path to location of page files',
      default: 'example',
      when: !this.data.path,
    }, {
      type: 'checkbox',
      name: 'markups',
      message: 'Page markup type:',
      choices: [{
        name: 'html',
        value: 'HTML',
      }, {
        name: 'jade',
        value: 'Jade',
      }, {
        name: 'nunjucks',
        value: 'Nunjucks',
      }],
      when: !this.data.markups || ['html', 'jade', 'nunjucks'].indexOf(this.data.markups) === -1,
    }, {
      type: 'checkbox',
      name: 'styles',
      message: 'Page style type:',
      choices: [{
        name: 'css',
        value: 'CSS',
      }, {
        name: 'sass',
        value: 'SASS',
      }, {
        name: 'scss',
        value: 'SCSS',
      }, {
        name: 'less',
        value: 'Less',
      }],
      when: !this.data.styles || ['css', 'sass', 'scss', 'less'].indexOf(this.data.styles) === -1,
    }];

    this.prompt(prompts, (answers) => {
      _.assign(this.data, answers);

      done();
    });
  }

  writing() {
    let out = path.join(this.data.site.src || 'src', this.data.path);
    switch (this.data.markups) {
      case 'jade':
        this._copyDirectory('jade', out);
        break;
      case 'nunjucks':
        this._copyDirectory('nunjucks', out);
        break;
      default:
        this._copyDirectory('html', out);
    }
    switch (this.data.styles) {
      case 'sass':
        this._copyDirectory('sass', out);
        break;
      case 'scss':
        this._copyDirectory('scss', out);
        break;
      case 'less':
        this._copyDirectory('less', out);
        break;
      default:
        this._copyDirectory('css', out);
    }
  }
};
<|endoftext|>


<commit_before>import ActionButton from './../components/ActionButton.js';
import ColorPicker from './../components/ColorPicker.js';
import Header from './../components/Header.js';
import Checkbox from './../components/Checkbox.js';
import Card from './../components/Card.js';
import Slider from './../components/Slider.js';

import React, { Component } from 'react';

class Home extends Component<{}, {}> {

  render() {
    return (

              <Card heading='Adjust Weightages'>
                <Slider id='circle' label='Circle weightage'/>
                <Slider id='parallelogram1' label='Paralellogram 1'/>
                <Slider id='parallelogram2' label='Paralellogram 2'/>
                <Slider id='quarterTopLeft' label='Top left quarter ring'/>
                <Slider id='quarterTopRight' label='Top right quarter ring'/>
                <Slider id='quarterBottomLeft' label='Bottom left quarter ring'/>
                <Slider id='quarterBottomRight' label='Bottom left quarter ring'/>
                <Slider id='colorFill' label='Color Fill '/>
                <Slider id='blank' label='Blank'/>
              </Card>

              <Card heading='Action buttons'>
                <ActionButton label='Generate Pattern' color='teal' selector='button' darken='0'/>
                <ActionButton label='Save Pattern' color='blue' selector='download' darken='1'/>
                <ActionButton label='Redraw Pattern' color='grey' selector='recreate' darken='3'/>
                <ActionButton label='Create New Grid' color='grey' selector='new' darken='3'/>
              </Card>

              <Card heading="Select shapes">
                <Checkbox id='circle-check' label='Circle weightage' checked={true}/>
                <Checkbox id='parallelogram1-check' label='Paralellogram 1' checked={true}/>
                <Checkbox id='parallelogram2-check' label='Paralellogram 2' checked={true}/>
                <Checkbox id='quarterTopLeft-check' label='Top left quarter ring' checked={true}/>
                <Checkbox id='quarterTopRight-check' label='Top right quarter ring' checked={true}/>
                <Checkbox id='quarterBottomLeft-check' label='Bottom left quarter ring' checked={true}/>
                <Checkbox id='quarterBottomRight-check' label='Bottom left quarter ring' checked={true}/>
                <Checkbox id='colorFill-check' label='Color Fill ' checked={true}/>
                <Checkbox id='blank-check' label='Blank' checked={true}/>
              </Card>

                  <Card heading='Pick a few colors'>
                    <ColorPicker />
                  </Card>

    );
  }
}

export default Home;
<commit_msg>changed file name<commit_after>import ActionButton from './../Components/ActionButton.js';
import ColorPicker from './../Components/ColorPicker.js';
import Header from './../Components/Header.js';
import Checkbox from './../Components/Checkbox.js';
import Card from './../Components/Card.js';
import Slider from './../Components/Slider.js';

import React, { Component } from 'react';

class Home extends Component<{}, {}> {

  render() {
    return (

              <Card heading='Adjust Weightages'>
                <Slider id='circle' label='Circle weightage'/>
                <Slider id='parallelogram1' label='Paralellogram 1'/>
                <Slider id='parallelogram2' label='Paralellogram 2'/>
                <Slider id='quarterTopLeft' label='Top left quarter ring'/>
                <Slider id='quarterTopRight' label='Top right quarter ring'/>
                <Slider id='quarterBottomLeft' label='Bottom left quarter ring'/>
                <Slider id='quarterBottomRight' label='Bottom left quarter ring'/>
                <Slider id='colorFill' label='Color Fill '/>
                <Slider id='blank' label='Blank'/>
              </Card>

              <Card heading='Action buttons'>
                <ActionButton label='Generate Pattern' color='teal' selector='button' darken='0'/>
                <ActionButton label='Save Pattern' color='blue' selector='download' darken='1'/>
                <ActionButton label='Redraw Pattern' color='grey' selector='recreate' darken='3'/>
                <ActionButton label='Create New Grid' color='grey' selector='new' darken='3'/>
              </Card>

              <Card heading="Select shapes">
                <Checkbox id='circle-check' label='Circle weightage' checked={true}/>
                <Checkbox id='parallelogram1-check' label='Paralellogram 1' checked={true}/>
                <Checkbox id='parallelogram2-check' label='Paralellogram 2' checked={true}/>
                <Checkbox id='quarterTopLeft-check' label='Top left quarter ring' checked={true}/>
                <Checkbox id='quarterTopRight-check' label='Top right quarter ring' checked={true}/>
                <Checkbox id='quarterBottomLeft-check' label='Bottom left quarter ring' checked={true}/>
                <Checkbox id='quarterBottomRight-check' label='Bottom left quarter ring' checked={true}/>
                <Checkbox id='colorFill-check' label='Color Fill ' checked={true}/>
                <Checkbox id='blank-check' label='Blank' checked={true}/>
              </Card>

                  <Card heading='Pick a few colors'>
                    <ColorPicker />
                  </Card>

    );
  }
}

export default Home;
<|endoftext|>


<commit_before>/* global Pebble navigator */
function pebbleSuccess(e) {
  // do nothing
}
function pebbleFailure(e) {
  console.error(e);
}

var reportPhoneBatt;

Pebble.addEventListener('ready', function(e) {
  if (navigator.getBattery) {
    navigator.getBattery().then(function (battery) {
      reportPhoneBatt = function () {
        Pebble.sendAppMessage({
          'PHONE_BATT_LEVEL': Math.floor(battery.level * 100),
          'PHONE_BATT_CHARGING': battery.charging ? 1 : 0
        }, pebbleSuccess, pebbleFailure);
      };
      battery.addEventListener('levelchange', function() {
        console.log('Level change: '+ (battery.level * 100) +'%');
        reportPhoneBatt();
      });
      battery.addEventListener('chargingchange', reportPhoneBatt);
    });
  } else {
    console.error('No navigator.getBattery');
    console.error('User agent: '+navigator.userAgent);
  }
});
Pebble.addEventListener('appmessage', function(e) {
  if (e.payload.QUERY_PHONE_BATT && reportPhoneBatt) {
    return reportPhoneBatt();
  }
});<commit_msg>Report phone battery on startup<commit_after>/* global Pebble navigator */
function pebbleSuccess(e) {
  // do nothing
}
function pebbleFailure(e) {
  console.error(e);
}

var reportPhoneBatt;

Pebble.addEventListener('ready', function(e) {
  if (navigator.getBattery) {
    navigator.getBattery().then(function (battery) {
      reportPhoneBatt = function () {
        Pebble.sendAppMessage({
          'PHONE_BATT_LEVEL': Math.floor(battery.level * 100),
          'PHONE_BATT_CHARGING': battery.charging ? 1 : 0
        }, pebbleSuccess, pebbleFailure);
      };
      battery.addEventListener('levelchange', function() {
        console.log('Level change: '+ (battery.level * 100) +'%');
        reportPhoneBatt();
      });
      battery.addEventListener('chargingchange', reportPhoneBatt);
      reportPhoneBatt();
    });
  } else {
    console.error('No navigator.getBattery');
    console.error('User agent: '+navigator.userAgent);
  }
});
Pebble.addEventListener('appmessage', function(e) {
  if (e.payload.QUERY_PHONE_BATT && reportPhoneBatt) {
    return reportPhoneBatt();
  }
});<|endoftext|>