<commit_before>/*!
 *  submono - a Web Audio subtractive, monophonic synthesizer
 *  (c) 2015 Benji Kay
 *  MIT License
 */

/*
 * TODO: Explore synth.cutoff.contour.
 */

var Monosynth = function Monosynth(audioCtx, config) {
  var synth;
  var Synth = function Synth() {
    synth = this;
    config = config || {};
    config.cutoff = config.cutoff || {};

    synth.audioCtx = audioCtx,
    synth.amp      = audioCtx.createGain(),
    synth.filter   = audioCtx.createBiquadFilter(),
    synth.osc      = audioCtx.createOscillator(),
    synth.pan      = audioCtx.createPanner(),

    synth.maxGain  = config.maxGain  || 0.9, // out of 1
    synth.attack   = config.attack   || 0.1, // in seconds
    synth.decay    = config.decay    || 0.0, // in seconds
    synth.sustain  = config.sustain  || 1.0, // out of 1
    synth.release  = config.release  || 0.8, // in seconds

    //low-pass filter
    synth.cutoff              = synth.filter.frequency;
    synth.cutoff.maxFrequency = config.cutoff.maxFrequency || 7500; // in hertz
    synth.cutoff.attack       = config.cutoff.attack       || 0.1; // in seconds
    synth.cutoff.decay        = config.cutoff.decay        || 2.5; // in seconds
    synth.cutoff.sustain      = config.cutoff.sustain      || 0.2; // out of 1

    synth.amp.gain.value = 0;
    synth.filter.type = 'lowpass';
    synth.filter.connect(synth.amp);
    synth.amp.connect(audioCtx.destination);
    synth.pan.panningModel = 'equalpower';
    synth.pan.setPosition(0, 0, 1); // start with stereo image centered
    synth.osc.connect(synth.pan);
    synth.pan.connect(synth.filter);
    synth.osc.start(0);

    synth.waveform(config.waveform || 'sine');
    synth.pitch(config.pitch || 440);

    return synth;
  };

  function getNow() {
    var now = synth.audioCtx.currentTime;
    synth.amp.gain.cancelScheduledValues(now);
    synth.amp.gain.setValueAtTime(synth.amp.gain.value, now);
    return now;
  };

  Synth.prototype.pitch = function pitch(newPitch) {
    if (newPitch) {
      var now = synth.audioCtx.currentTime;
      synth.osc.frequency.setValueAtTime(newPitch, now);
    }
    return synth.osc.frequency.value;
  };

  Synth.prototype.waveform = function waveform(newWaveform) {
    if (newWaveform) {
      synth.osc.type = newWaveform;
    }
    return synth.osc.type;
  };

  //apply attack, decay, sustain envelope
  Synth.prototype.start = function startSynth() {
    var atk  = parseFloat(synth.attack);
    var dec  = parseFloat(synth.decay);
    var cAtk = parseFloat(synth.cutoff.attack);
    var cDec = parseFloat(synth.cutoff.decay);
    var now  = getNow();
    synth.cutoff.cancelScheduledValues(now);
    synth.cutoff.linearRampToValueAtTime(synth.cutoff.value, now);
    synth.cutoff.linearRampToValueAtTime(synth.cutoff.maxFrequency, now + cAtk);
    synth.cutoff.linearRampToValueAtTime(synth.cutoff.sustain * synth.cutoff.maxFrequency, now + cAtk + cDec);
    synth.amp.gain.linearRampToValueAtTime(synth.maxGain, now + atk);
    synth.amp.gain.linearRampToValueAtTime(synth.sustain * synth.maxGain, now + atk + dec);
  };

  //apply release envelope
  Synth.prototype.stop = function stopSynth() {
    var rel = parseFloat(synth.release);
    var now = getNow();
    synth.amp.gain.linearRampToValueAtTime(0, now + rel);
  };

  return new Synth();
};
<commit_msg>remove todo (tracked elsewhere)<commit_after>/*!
 *  submono - a Web Audio subtractive, monophonic synthesizer
 *  (c) 2015 Benji Kay
 *  MIT License
 */

var Monosynth = function Monosynth(audioCtx, config) {
  var synth;
  var Synth = function Synth() {
    synth = this;
    config = config || {};
    config.cutoff = config.cutoff || {};

    synth.audioCtx = audioCtx,
    synth.amp      = audioCtx.createGain(),
    synth.filter   = audioCtx.createBiquadFilter(),
    synth.osc      = audioCtx.createOscillator(),
    synth.pan      = audioCtx.createPanner(),

    synth.maxGain  = config.maxGain  || 0.9, // out of 1
    synth.attack   = config.attack   || 0.1, // in seconds
    synth.decay    = config.decay    || 0.0, // in seconds
    synth.sustain  = config.sustain  || 1.0, // out of 1
    synth.release  = config.release  || 0.8, // in seconds

    //low-pass filter
    synth.cutoff              = synth.filter.frequency;
    synth.cutoff.maxFrequency = config.cutoff.maxFrequency || 7500; // in hertz
    synth.cutoff.attack       = config.cutoff.attack       || 0.1; // in seconds
    synth.cutoff.decay        = config.cutoff.decay        || 2.5; // in seconds
    synth.cutoff.sustain      = config.cutoff.sustain      || 0.2; // out of 1

    synth.amp.gain.value = 0;
    synth.filter.type = 'lowpass';
    synth.filter.connect(synth.amp);
    synth.amp.connect(audioCtx.destination);
    synth.pan.panningModel = 'equalpower';
    synth.pan.setPosition(0, 0, 1); // start with stereo image centered
    synth.osc.connect(synth.pan);
    synth.pan.connect(synth.filter);
    synth.osc.start(0);

    synth.waveform(config.waveform || 'sine');
    synth.pitch(config.pitch || 440);

    return synth;
  };

  function getNow() {
    var now = synth.audioCtx.currentTime;
    synth.amp.gain.cancelScheduledValues(now);
    synth.amp.gain.setValueAtTime(synth.amp.gain.value, now);
    return now;
  };

  Synth.prototype.pitch = function pitch(newPitch) {
    if (newPitch) {
      var now = synth.audioCtx.currentTime;
      synth.osc.frequency.setValueAtTime(newPitch, now);
    }
    return synth.osc.frequency.value;
  };

  Synth.prototype.waveform = function waveform(newWaveform) {
    if (newWaveform) {
      synth.osc.type = newWaveform;
    }
    return synth.osc.type;
  };

  //apply attack, decay, sustain envelope
  Synth.prototype.start = function startSynth() {
    var atk  = parseFloat(synth.attack);
    var dec  = parseFloat(synth.decay);
    var cAtk = parseFloat(synth.cutoff.attack);
    var cDec = parseFloat(synth.cutoff.decay);
    var now  = getNow();
    synth.cutoff.cancelScheduledValues(now);
    synth.cutoff.linearRampToValueAtTime(synth.cutoff.value, now);
    synth.cutoff.linearRampToValueAtTime(synth.cutoff.maxFrequency, now + cAtk);
    synth.cutoff.linearRampToValueAtTime(synth.cutoff.sustain * synth.cutoff.maxFrequency, now + cAtk + cDec);
    synth.amp.gain.linearRampToValueAtTime(synth.maxGain, now + atk);
    synth.amp.gain.linearRampToValueAtTime(synth.sustain * synth.maxGain, now + atk + dec);
  };

  //apply release envelope
  Synth.prototype.stop = function stopSynth() {
    var rel = parseFloat(synth.release);
    var now = getNow();
    synth.amp.gain.linearRampToValueAtTime(0, now + rel);
  };

  return new Synth();
};
<|endoftext|>


<commit_before>'use strict';
const
  phantom       = require('phantom'),
  cluster       = require('cluster'),
  express       = require('express'),
  http          = require('http'),
  numCPUs       = require('os').cpus().length,
  MobileDetect  = require('mobile-detect'),
  mime          = require('mime-types'),
  app           = express();

//Regex
var SCRIPT_REGEX   = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
var ASSET_REGEX    = /\.(jpg|jpeg|png|gif|css|js|woff|\/img|\/css|\/js)/g;
var ESCAPED_REGEX  = /escaped_fragment_=/g;
var ERR404_REGEX   = /name="prerender-status-code/g;

// Url of the single page application
var ORIGIN      = process.env.ORIGIN || 'http://localhost:3000/';
var port        = process.env.PORT || 1333;
//PhantomJS arguments
var pharguments = ["--load-images=false", "--ignore-ssl-errors=true", "--ssl-protocol=tlsv1"];

//-----------------------------------------------------

if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++) { cluster.fork(); }

    cluster.on('exit', function (worker) {
        console.log('Worker %d died :( restarting...', worker.id);
        cluster.fork();
    });

} else {

    var processingQueue = [];
    phantom.create(function (ph) {

        ph.createPage(function (page) {

            page.open(ORIGIN, function (status) {
                    console.log("Swayzee has awakened and is looking for "+ORIGIN+"...");

                    app.get('*', function(req, res) {
                        var hasEscapedFragment = req.url.match(ESCAPED_REGEX);
                        var isAsset            = mime.lookup(req.url);

                        if (hasEscapedFragment && !isAsset) {
                            console.log("Receiving :",req.url);
                            var hash = extractHashURL(req.url);
                            processingQueue.push({hash: hash, request: req, response: res, page: page, running: false})
                            processNext();
                        } else {
                            //Redirect asset requests to origin, only works for 2 level path assets ex: /img/avatar.jpg
                            var redirect_url = calcRedirectUrl(req.url)
                            res.redirect(redirect_url);
                        }

                    });

                    app.listen( port, function(){ console.log("Swayzee is ready to receive requests."); });
           });

           // HANDLE PHANTOM OUTPUT
           page.set('onConsoleMessage', function (msg) {
                // Uncomment for debuging your client output
                console.log("Phantom Console: " + msg);
                if (msg.indexOf('PEF: ') > -1) {
                    var hash = msg.replace('PEF: ','').split(' -@- ')[0];
                    var html = msg.replace('PEF: ','').split(' -@- ')[1];
                    var task = processingQueue.shift();

                    if (hash == task.hash) {
                        html = removeScriptTags(html);
                        generateResponse(task, html);
                    }
                }
           });
       });

    }, pharguments);

    process.on('SIGINT', function() {
        console.log("Closing ");
        require('child_process').spawn('pkill', ['phantomjs']);
        process.exit();
    });
}

// FETCH AND RENDER PAGE (RECURSIVE),
var fetchAndRenderPage = function(page, hash, size) {
    console.log("Swayzee has is now stalking ", hash);
    page.set('viewportSize', size);

    page.evaluate(function(hash){
        var previousTitle = document.title;
        var iteration=0;
        window.location.hash = hash;

        function isRenderReady() {
            // console.log(iteration+") Title : ",previousTitle, ' vs ',document.title);
            if( previousTitle===document.title && iteration < 40) {
                iteration++;
                setTimeout(isRenderReady, 50);
            } else {
                setTimeout(function(){
                    console.log("PEF: "+hash+" -@- "+document.documentElement.innerHTML);
                    document.title =  document.title+' processed '+Date.now()
                    return;
                }, 1500);
            }
        }
        isRenderReady();
    }, function (result) {}, hash);
}

// Process the next task in the queue
var processNext = function(){
    if (processingQueue.length > 0) {
        var task = processingQueue[0];
        if (task.running == false) {
            var size = calcScreenSize(task.request);
            fetchAndRenderPage(task.page, task.hash, size);
            task.running = true;
        }
    }
}

// Detects the size of the screen and applies a custom width to the phantom page
var calcScreenSize = function(request) {
    var md = new MobileDetect(request.headers['user-agent']);
    var size = { width: 1440, height: 718 };
    if (md.phone()){
        console.log("Mobile size detected.");
        size = { width: 479, height: 718 };
    } else if (md.tablet()) {
        console.log("Tablet size detected.");
        size = { width: 961, height: 718 };
    }
    return size;
}

// Removes all script tags from the html
var removeScriptTags = function(html) {
    while (SCRIPT_REGEX.test(html)) { html = html.replace(SCRIPT_REGEX, ""); }
    return html;
}

// Extracts the hash and adds back the #! convention
var extractHashURL = function(url) {
    return  '#!'+url.split("_escaped_fragment_=")[1];
}

// Calcs the origin url of the requested resource
var calcRedirectUrl = function(url) {
    var splited = url.split("/");
    return ORIGIN+(splited[splited.length-2])+"/"+(splited[splited.length-1]);
}

// Handles the task response, detects also 404
var generateResponse = function(task, html){
    console.log("Response ready for ", task.hash);
    if (html.match(ERR404_REGEX)) {
      task.response.status(404).send(html);
    } else {
      task.response.status(200).send(html);
    }
}

<commit_msg>Mime module added, asset regex not needed anymore<commit_after>'use strict';
const
  phantom       = require('phantom'),
  cluster       = require('cluster'),
  express       = require('express'),
  http          = require('http'),
  numCPUs       = require('os').cpus().length,
  MobileDetect  = require('mobile-detect'),
  mime          = require('mime-types'),
  app           = express();

//Regex
var SCRIPT_REGEX   = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
var ESCAPED_REGEX  = /escaped_fragment_=/g;
var ERR404_REGEX   = /name="prerender-status-code/g;

// Url of the single page application
var ORIGIN      = process.env.ORIGIN || 'http://localhost:3000/';
var port        = process.env.PORT || 1333;
//PhantomJS arguments
var pharguments = ["--load-images=false", "--ignore-ssl-errors=true", "--ssl-protocol=tlsv1"];

//-----------------------------------------------------

if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++) { cluster.fork(); }

    cluster.on('exit', function (worker) {
        console.log('Worker %d died :( restarting...', worker.id);
        cluster.fork();
    });

} else {

    var processingQueue = [];
    phantom.create(function (ph) {

        ph.createPage(function (page) {

            page.open(ORIGIN, function (status) {
                    console.log("Swayzee has awakened and is looking for "+ORIGIN+"...");

                    app.get('*', function(req, res) {
                        var hasEscapedFragment = req.url.match(ESCAPED_REGEX);
                        var isAsset            = mime.lookup(req.url);

                        if (hasEscapedFragment && !isAsset) {
                            console.log("Receiving :",req.url);
                            var hash = extractHashURL(req.url);
                            processingQueue.push({hash: hash, request: req, response: res, page: page, running: false})
                            processNext();
                        } else {
                            //Redirect asset requests to origin, only works for 2 level path assets ex: /img/avatar.jpg
                            var redirect_url = calcRedirectUrl(req.url)
                            res.redirect(redirect_url);
                        }

                    });

                    app.listen( port, function(){ console.log("Swayzee is ready to receive requests."); });
           });

           // HANDLE PHANTOM OUTPUT
           page.set('onConsoleMessage', function (msg) {
                // Uncomment for debuging your client output
                console.log("Phantom Console: " + msg);
                if (msg.indexOf('PEF: ') > -1) {
                    var hash = msg.replace('PEF: ','').split(' -@- ')[0];
                    var html = msg.replace('PEF: ','').split(' -@- ')[1];
                    var task = processingQueue.shift();

                    if (hash == task.hash) {
                        html = removeScriptTags(html);
                        generateResponse(task, html);
                    }
                }
           });
       });

    }, pharguments);

    process.on('SIGINT', function() {
        console.log("Closing ");
        require('child_process').spawn('pkill', ['phantomjs']);
        process.exit();
    });
}

// FETCH AND RENDER PAGE (RECURSIVE),
var fetchAndRenderPage = function(page, hash, size) {
    console.log("Swayzee has is now stalking ", hash);
    page.set('viewportSize', size);

    page.evaluate(function(hash){
        var previousTitle = document.title;
        var iteration=0;
        window.location.hash = hash;

        function isRenderReady() {
            // console.log(iteration+") Title : ",previousTitle, ' vs ',document.title);
            if( previousTitle===document.title && iteration < 40) {
                iteration++;
                setTimeout(isRenderReady, 50);
            } else {
                setTimeout(function(){
                    console.log("PEF: "+hash+" -@- "+document.documentElement.innerHTML);
                    document.title =  document.title+' processed '+Date.now()
                    return;
                }, 1500);
            }
        }
        isRenderReady();
    }, function (result) {}, hash);
}

// Process the next task in the queue
var processNext = function(){
    if (processingQueue.length > 0) {
        var task = processingQueue[0];
        if (task.running == false) {
            var size = calcScreenSize(task.request);
            fetchAndRenderPage(task.page, task.hash, size);
            task.running = true;
        }
    }
}

// Detects the size of the screen and applies a custom width to the phantom page
var calcScreenSize = function(request) {
    var md = new MobileDetect(request.headers['user-agent']);
    var size = { width: 1440, height: 718 };
    if (md.phone()){
        console.log("Mobile size detected.");
        size = { width: 479, height: 718 };
    } else if (md.tablet()) {
        console.log("Tablet size detected.");
        size = { width: 961, height: 718 };
    }
    return size;
}

// Removes all script tags from the html
var removeScriptTags = function(html) {
    while (SCRIPT_REGEX.test(html)) { html = html.replace(SCRIPT_REGEX, ""); }
    return html;
}

// Extracts the hash and adds back the #! convention
var extractHashURL = function(url) {
    return  '#!'+url.split("_escaped_fragment_=")[1];
}

// Calcs the origin url of the requested resource
var calcRedirectUrl = function(url) {
    var splited = url.split("/");
    return ORIGIN+(splited[splited.length-2])+"/"+(splited[splited.length-1]);
}

// Handles the task response, detects also 404
var generateResponse = function(task, html){
    console.log("Response ready for ", task.hash);
    if (html.match(ERR404_REGEX)) {
      task.response.status(404).send(html);
    } else {
      task.response.status(200).send(html);
    }
}

<|endoftext|>


<commit_before>import { isFunction } from './typeof.js';
import { registry } from './registry.js';

const CONNECTED = 'connectedCallback';
const DISCONNECTED = 'disconnectedCallback';
const UPDATED = 'attributeChangedCallback';

export function getComponent(node) {
    if (node.nodeType === Node.ELEMENT_NODE) {
        let is = node.getAttribute('is') || node.tagName;
        return registry.get(is);
    }
    return null;
}

export function connect(node) {
    if (isFunction(node[CONNECTED])) {
        node[CONNECTED]();
    }
}

export function disconnect(node) {
    if (isFunction(node[DISCONNECTED])) {
        node[DISCONNECTED]();
    }
}

export function update(node, name, oldValue, newValue) {
    if (isFunction(node[UPDATED]) && name !== 'is') {
        node[UPDATED](name, oldValue, newValue);
    }
}

export function bind(node, Ctr) {
    node.__proto__ = Ctr.prototype;
    Object.defineProperty(node, 'constructor', {
        value: Ctr,
        configurable: true,
        writable: true,
    });
    Ctr.call(node);
}

export function create(node, descriptor) {
    descriptor = descriptor || getComponent(node);
    if (descriptor) {
        bind(node, descriptor.Ctr);
        connect(node);
    }
}

export function appendChild(parent, node) {
    if (parent !== node.parentNode || parent.lastElementChild !== node) {
        if (node.parentNode) {
            removeChild(node.parentNode, node);
        }
        parent.appendChild(node);
        connect(node);
    }
}

export function removeChild(parent, node) {
    parent.removeChild(node);
    disconnect(node);
}
<commit_msg>feat: add attribute methods to nodes lib<commit_after>import { isFunction } from './typeof.js';
import { registry } from './registry.js';

const CONNECTED = 'connectedCallback';
const DISCONNECTED = 'disconnectedCallback';
const UPDATED = 'attributeChangedCallback';

export function getComponent(node) {
    if (node.nodeType === Node.ELEMENT_NODE) {
        let is = node.getAttribute('is') || node.tagName;
        return registry.get(is);
    }
    return registry.get(node);
}

export function connect(node) {
    if (isFunction(node[CONNECTED])) {
        node[CONNECTED].call(node);
    }
}

export function disconnect(node) {
    if (isFunction(node[DISCONNECTED])) {
        node[DISCONNECTED].call(node);
    }
}

export function update(node, name, oldValue, newValue) {
    if (isFunction(node[UPDATED]) && name !== 'is') {
        node[UPDATED].call(node, name, oldValue, newValue);
    }
}

export function bind(node, Ctr) {
    node.__proto__ = Ctr.prototype;
    Object.defineProperty(node, 'constructor', {
        value: Ctr,
        configurable: true,
        writable: true,
    });
    Ctr.call(node);
}

export function create(node, descriptor) {
    descriptor = descriptor || getComponent(node);
    if (descriptor) {
        bind(node, descriptor.Ctr);
        connect(node);
    }
}

export function createElement(is) {
    let descriptor = getComponent(is);
    if (descriptor) {
        return new descriptor.Ctr();
    }
}

export function appendChild(parent, node) {
    if (parent !== node.parentNode || parent.lastElementChild !== node) {
        if (node.parentNode) {
            removeChild(node.parentNode, node);
        }
        parent.appendChild(node);
        connect(node);
    }
}

export function removeChild(parent, node) {
    parent.removeChild(node);
    disconnect(node);
}

export function setAttribute(node, name, value) {
    let oldValue = node.getAttribute(name);
    node.setAttribute(name, value);
    let attrs = node.constructor.observedAttributes || [];
    if (attrs.indexOf(name) !== -1) {
        update(node, name, oldValue, value);
    }
}

export function removeAttribute(node, name) {
    let oldValue = node.getAttribute(name);
    node.removeAttribute(name);
    let attrs = node.constructor.observedAttributes || [];
    if (attrs.indexOf(name) !== -1) {
        update(node, name, oldValue, null);
    }
}
<|endoftext|>


<commit_before>// From: https://gist.github.com/Fluidbyte/2973986
import currencyCodes from 'lib/currency-codes.json';

export function intToAmount(amount, currency = 'GBP') {
  if (amount === undefined || amount === null || amount === false) {
    return false;
  }

  const currencySymbol = currencyCodes[currency].symbol;
  let addition = false;

  amount = String(amount);

  // See if it's an addition to the account
  if (!amount.includes('-') && amount !== '0') {
    addition = true;
  }

  // Remove the minus
  amount = amount.replace('-', '');

  // Format it with decimal places
  let formattedAmount = amount.length > 2 ?
    `${amount.substr(0, amount.length - 2)}.${amount.substr(-2)}` : amount;

  return `${addition ? '+ ' : ''}${currencySymbol}${formattedAmount}`;
}

// From Underscore.js - saves importing the whole lib!
export function once(func) {
  let ran = false, memo;
  return function() {
    if (ran) return memo;
    ran = true;
    memo = func.apply(this, arguments);
    func = null;
    return memo;
  };
};
<commit_msg>(#21) - Fix amounts less than £1 being shown incorrectly<commit_after>// From: https://gist.github.com/Fluidbyte/2973986
import currencyCodes from 'lib/currency-codes.json';

export function intToAmount(amount, currency = 'GBP') {
  if (amount === undefined || amount === null || amount === false) {
    return false;
  }

  const currencySymbol = currencyCodes[currency].symbol;
  let addition = false;

  amount = String(amount);

  // See if it's an addition to the account
  if (!amount.includes('-') && amount !== '0') {
    addition = true;
  }

  // Remove the minus
  amount = amount.replace('-', '');

  // Format it with decimal places
  let formattedAmount = amount.length > 2 ?
    `${amount.substr(0, amount.length - 2)}.${amount.substr(-2)}` :
    amount.length === 2 ? `0.${amount}` : `0.0${amount}`;

  return `${addition ? '+ ' : ''}${currencySymbol}${formattedAmount}`;
}

// From Underscore.js - saves importing the whole lib!
export function once(func) {
  let ran = false, memo;
  return function() {
    if (ran) return memo;
    ran = true;
    memo = func.apply(this, arguments);
    func = null;
    return memo;
  };
};
<|endoftext|>


<commit_before>var curTimer = null;
var statusMessage = function(message, time) {
    time = (typeof time === 'undefined') ? 1500 : time;
    var element = document.getElementById('status');
    if (curTimer)
        clearTimeout(curTimer);
    element.innerText = message;
    var timer = setTimeout(function() {
        element.innerText = '';
        curTimer = null;
    }, time);
    curTimer = timer;
};

var saveOptions = function() {
    var options = Object.create(null);
    options['omitZeroComments'] = document.getElementById('omitZeroComments-checkbox').checked;
    chrome.storage.local.set({options: options});
};

var loadOptions = function(options) {
    document.getElementById('omitZeroComments-checkbox').checked = options['omitZeroComments'];
    // options must be saved when loaded to keep everything in sync
    // (since there is no specific "save" button")
    // onchange/oninput won't fire when loading options with javascript,
    // so trigger saveOptions manually
    saveOptions();
};

document.addEventListener('DOMContentLoaded', function() {
    chrome.storage.local.get(['options'], function(result) {
        var initOpts = result.options;
        // restore saved options
        loadOptions(initOpts);

        // load default options
        document.getElementById('defaults').addEventListener('click', function() {
            var defaults = chrome.extension.getBackgroundPage().defaultOptions();
            loadOptions(defaults);
            statusMessage('Defaults Loaded', 1200);
        });

        document.getElementById('revert').addEventListener('click', function() {
            loadOptions(initOpts);
            statusMessage('Options Reverted', 1200);
        });
    });
});

// save options on any user input
(function() {
    var inputs = document.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; i++) {
        var input = inputs[i];
        input.addEventListener('change', saveOptions);
        input.addEventListener('input', saveOptions);
    }
})();

// version
document.getElementById('version').innerText = chrome.runtime.getManifest().version;
<commit_msg>Decouple label for touch devices.<commit_after>var curTimer = null;
var statusMessage = function(message, time) {
    time = (typeof time === 'undefined') ? 1500 : time;
    var element = document.getElementById('status');
    if (curTimer)
        clearTimeout(curTimer);
    element.innerText = message;
    var timer = setTimeout(function() {
        element.innerText = '';
        curTimer = null;
    }, time);
    curTimer = timer;
};

var saveOptions = function() {
    var options = Object.create(null);
    options['omitZeroComments'] = document.getElementById('omitZeroComments-checkbox').checked;
    chrome.storage.local.set({options: options});
};

var loadOptions = function(options) {
    document.getElementById('omitZeroComments-checkbox').checked = options['omitZeroComments'];
    // options must be saved when loaded to keep everything in sync
    // (since there is no specific "save" button")
    // onchange/oninput won't fire when loading options with javascript,
    // so trigger saveOptions manually
    saveOptions();
};

document.addEventListener('DOMContentLoaded', function() {
    chrome.storage.local.get(['options'], function(result) {
        var initOpts = result.options;
        // restore saved options
        loadOptions(initOpts);

        // load default options
        document.getElementById('defaults').addEventListener('click', function() {
            var defaults = chrome.extension.getBackgroundPage().defaultOptions();
            loadOptions(defaults);
            statusMessage('Defaults Loaded', 1200);
        });

        document.getElementById('revert').addEventListener('click', function() {
            loadOptions(initOpts);
            statusMessage('Options Reverted', 1200);
        });
    });

    // decouple label for touch devices, since clicking shows the tooltip.
    if (window.matchMedia('(pointer: coarse)').matches) {
        let toRemove = new Set(['omitZeroComments-checkbox']);
        let labels = document.getElementsByTagName('label');
        for (let i = 0; i < labels.length; ++i) {
            if (toRemove.has(labels[i].htmlFor))
                labels[i].removeAttribute('for');
        }
    }
});

// save options on any user input
(function() {
    var inputs = document.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; i++) {
        var input = inputs[i];
        input.addEventListener('change', saveOptions);
        input.addEventListener('input', saveOptions);
    }
})();

// version
document.getElementById('version').innerText = chrome.runtime.getManifest().version;
<|endoftext|>


<commit_before>'use strict';

import data from './data';
import MutationObserver from './mutation-observer';
import {
  addClass,
  inherit,
  objEach
} from './utils';

var elProto = window.HTMLElement.prototype;
var matchesSelector = (
    elProto.matches ||
    elProto.msMatchesSelector ||
    elProto.webkitMatchesSelector ||
    elProto.mozMatchesSelector ||
    elProto.oMatchesSelector
  );

function getLifecycleFlag (target, component, name) {
  return data.get(target, component.id + ':lifecycle:' + name);
}

function setLifecycleFlag (target, component, name, value) {
  data.set(target, component.id + ':lifecycle:' + name, !!value);
}

function ensureLifecycleFlag (target, component, name) {
  if (getLifecycleFlag(target, component, name)) {
    return true;
  }
  setLifecycleFlag(target, component, name, true);
  return false;
}

/**
 * Parses an event definition and returns information about it.
 *
 * @param {String} e The event to parse.
 *
 * @returns {Object]}
 */
function parseEvent (e) {
  var parts = e.split(' ');
  return {
    name: parts.shift(),
    delegate: parts.join(' ')
  };
}

/**
 * Binds attribute listeners for the specified attribute handlers.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function addAttributeListeners (target, component) {
  function triggerCallback (type, name, newValue, oldValue) {
    var callback;

    if (component.attributes && component.attributes[name] && typeof component.attributes[name][type] === 'function') {
      callback = component.attributes[name][type];
    } else if (component.attributes && typeof component.attributes[name] === 'function') {
      callback = component.attributes[name];
    } else if (typeof component.attributes === 'function') {
      callback = component.attributes;
    }

    // There may still not be a callback.
    if (callback) {
      callback(target, {
        type: type,
        name: name,
        newValue: newValue,
        oldValue: oldValue
      });
    }
  }

  var attrs = target.attributes;
  var attrsLen = attrs.length;
  var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      var type;
      var name = mutation.attributeName;
      var attr = attrs[name];

      if (attr && mutation.oldValue === null) {
        type = 'insert';
      } else if (attr && mutation.oldValue !== null) {
        type = 'update';
      } else if (!attr) {
        type = 'remove';
      }

      triggerCallback(type, name, attr ? (attr.value || attr.nodeValue) : undefined, mutation.oldValue);
    });
  });

  observer.observe(target, {
    attributes: true,
    attributeOldValue: true
  });

  // In default web components, attribute changes aren't triggered for
  // attributes that already exist on an element when it is bound. This sucks
  // when you want to reuse and separate code for attributes away from your
  // lifecycle callbacks. Skate will initialise each attribute calling the
  // "insert" callback that already exists on the element.
  for (var a = 0; a < attrsLen; a++) {
    var attr = attrs[a];

    // If an attribute is removed during the enumeration, then we must ensure
    // that each one still exists when it comes time to action it.
    if (attr) {
      triggerCallback('insert', attr.nodeName, (attr.value || attr.nodeValue));
    }
  }
}

/**
 * Binds event listeners for the specified event handlers.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function addEventListeners (target, component) {
  if (typeof component.events !== 'object') {
    return;
  }

  function makeHandler (handler, delegate) {
    return function (e) {
      // If we're not delegating, trigger directly on the component element.
      if (!delegate) {
        return handler(target, e, target);
      }

      // If we're delegating, but the target doesn't match, then we've have
      // to go up the tree until we find a matching ancestor or stop at the
      // component element, or document. If a matching ancestor is found, the
      // handler is triggered on it.
      var current = e.target;

      while (current && current !== document && current !== target) {
        if (matchesSelector.call(current, delegate)) {
          return handler(target, e, current);
        }

        current = current.parentNode;
      }
    };
  }

  objEach(component.events, function (handler, name) {
    var evt = parseEvent(name);
    target.addEventListener(evt.name, makeHandler(handler, evt.delegate));
  });
}

/**
 * Triggers the ready lifecycle callback.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerReady (target, component) {
  if (ensureLifecycleFlag(target, component, 'ready')) {
    return;
  }

  inherit(target, component.prototype);

  if (component.template) {
    component.template(target);
  }

  addEventListeners(target, component);
  addAttributeListeners(target, component);

  if (component.ready) {
    component.ready(target);
  }
}

/**
 * Triggers the insert lifecycle callback.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerInsert (target, component) {
  if (ensureLifecycleFlag(target, component, 'insert')) {
    return;
  }

  addClass(target, component.classname);

  if (component.insert) {
    component.insert(target);
  }
}

/**
 * Triggers the remove lifecycle callback.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerRemove (target, component) {
  if (component.remove) {
    component.remove(target);
    setLifecycleFlag(target, component, 'insert', false);
  }
}

/**
 * Triggers the entire element lifecycle if it's not being ignored.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerLifecycle (target, component) {
  triggerReady(target, component);
  triggerInsert(target, component);
}

export {
  triggerLifecycle,
  triggerReady,
  triggerRemove
};
<commit_msg>Reset insert flag regardless of if there is a remove callback.<commit_after>'use strict';

import data from './data';
import MutationObserver from './mutation-observer';
import {
  addClass,
  inherit,
  objEach
} from './utils';

var elProto = window.HTMLElement.prototype;
var matchesSelector = (
    elProto.matches ||
    elProto.msMatchesSelector ||
    elProto.webkitMatchesSelector ||
    elProto.mozMatchesSelector ||
    elProto.oMatchesSelector
  );

function getLifecycleFlag (target, component, name) {
  return data.get(target, component.id + ':lifecycle:' + name);
}

function setLifecycleFlag (target, component, name, value) {
  data.set(target, component.id + ':lifecycle:' + name, !!value);
}

function ensureLifecycleFlag (target, component, name) {
  if (getLifecycleFlag(target, component, name)) {
    return true;
  }
  setLifecycleFlag(target, component, name, true);
  return false;
}

/**
 * Parses an event definition and returns information about it.
 *
 * @param {String} e The event to parse.
 *
 * @returns {Object]}
 */
function parseEvent (e) {
  var parts = e.split(' ');
  return {
    name: parts.shift(),
    delegate: parts.join(' ')
  };
}

/**
 * Binds attribute listeners for the specified attribute handlers.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function addAttributeListeners (target, component) {
  function triggerCallback (type, name, newValue, oldValue) {
    var callback;

    if (component.attributes && component.attributes[name] && typeof component.attributes[name][type] === 'function') {
      callback = component.attributes[name][type];
    } else if (component.attributes && typeof component.attributes[name] === 'function') {
      callback = component.attributes[name];
    } else if (typeof component.attributes === 'function') {
      callback = component.attributes;
    }

    // There may still not be a callback.
    if (callback) {
      callback(target, {
        type: type,
        name: name,
        newValue: newValue,
        oldValue: oldValue
      });
    }
  }

  var attrs = target.attributes;
  var attrsLen = attrs.length;
  var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      var type;
      var name = mutation.attributeName;
      var attr = attrs[name];

      if (attr && mutation.oldValue === null) {
        type = 'insert';
      } else if (attr && mutation.oldValue !== null) {
        type = 'update';
      } else if (!attr) {
        type = 'remove';
      }

      triggerCallback(type, name, attr ? (attr.value || attr.nodeValue) : undefined, mutation.oldValue);
    });
  });

  observer.observe(target, {
    attributes: true,
    attributeOldValue: true
  });

  // In default web components, attribute changes aren't triggered for
  // attributes that already exist on an element when it is bound. This sucks
  // when you want to reuse and separate code for attributes away from your
  // lifecycle callbacks. Skate will initialise each attribute calling the
  // "insert" callback that already exists on the element.
  for (var a = 0; a < attrsLen; a++) {
    var attr = attrs[a];

    // If an attribute is removed during the enumeration, then we must ensure
    // that each one still exists when it comes time to action it.
    if (attr) {
      triggerCallback('insert', attr.nodeName, (attr.value || attr.nodeValue));
    }
  }
}

/**
 * Binds event listeners for the specified event handlers.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function addEventListeners (target, component) {
  if (typeof component.events !== 'object') {
    return;
  }

  function makeHandler (handler, delegate) {
    return function (e) {
      // If we're not delegating, trigger directly on the component element.
      if (!delegate) {
        return handler(target, e, target);
      }

      // If we're delegating, but the target doesn't match, then we've have
      // to go up the tree until we find a matching ancestor or stop at the
      // component element, or document. If a matching ancestor is found, the
      // handler is triggered on it.
      var current = e.target;

      while (current && current !== document && current !== target) {
        if (matchesSelector.call(current, delegate)) {
          return handler(target, e, current);
        }

        current = current.parentNode;
      }
    };
  }

  objEach(component.events, function (handler, name) {
    var evt = parseEvent(name);
    target.addEventListener(evt.name, makeHandler(handler, evt.delegate));
  });
}

/**
 * Triggers the ready lifecycle callback.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerReady (target, component) {
  if (ensureLifecycleFlag(target, component, 'ready')) {
    return;
  }

  inherit(target, component.prototype);

  if (component.template) {
    component.template(target);
  }

  addEventListeners(target, component);
  addAttributeListeners(target, component);

  if (component.ready) {
    component.ready(target);
  }
}

/**
 * Triggers the insert lifecycle callback.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerInsert (target, component) {
  if (ensureLifecycleFlag(target, component, 'insert')) {
    return;
  }

  addClass(target, component.classname);

  if (component.insert) {
    component.insert(target);
  }
}

/**
 * Triggers the remove lifecycle callback.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerRemove (target, component) {
  if (component.remove) {
    component.remove(target);
  }

  setLifecycleFlag(target, component, 'insert', false);
}

/**
 * Triggers the entire element lifecycle if it's not being ignored.
 *
 * @param {Element} target The component element.
 * @param {Object} component The component data.
 *
 * @returns {undefined}
 */
function triggerLifecycle (target, component) {
  triggerReady(target, component);
  triggerInsert(target, component);
}

export {
  triggerLifecycle,
  triggerReady,
  triggerRemove
};
<|endoftext|>


<commit_before>var _ = require( 'lodash' );
var path = require( 'path' );
var Base = require( '../../lib/base' );
var chalk = require( 'chalk' );

module.exports = Base.extend({
	pullMap: {
		'uploads': '_getUploads',
		'db': '_getSQL',
	},
	_initialize: function() {
		this.addRunMethod(
			'pull',
			this._doPull,
			'default'
		);
	},
	_doPull: function( done ) {
		var pulls = _.remove( this.arguments.map( this._getPull, this ) );

		if ( 1 > pulls.length ) {
			return done();
		}

		this.multiDownload( pulls )
			.then( done )
			.catch( function( err ){
				this.log( err.message );
				process.exit( 0 );
			}.bind( this ));
	},
	_getPull: function( pull ) {
		if ( this.pullMap[ pull ] ) {
			return this[ this.pullMap[ pull ] ]();
		} else {
			return false;
		}
	},
	_getUploads: function() {
		var uploads = false;
		if ( this.install.uploads ) {
			if ( 'string' === typeof this.install.uploads ) {
				uploads = { location: this.install.uploads };
			} else {
				uploads = _.clone( this.install.uploads );
			}
			uploads.dest = this.getAppPath( 'content-path', 'app', 'uploads' );
			uploads.opts = uploads.opts || {};
			uploads.opts.extract = { strip: 1 };
		}
		return uploads;
	},
	_getSQL: function() {
		var database = false;
		if ( this.install.database ) {
			if ( 'string' ===  typeof this.install.database ) {
				database = { location: this.install.database };
			} else {
				database = _.clone( this.install.database );
			}
			database.dest = path.join( 'config', 'data' );
		}
		if ( this.isRoot ) {
			this.addRunMethod( 'import', this._import, 'install' );
		}
		return database;
	},
	_import: function( done ){
		console.log();
		console.log( chalk.yellow( 'Attempting to import your database.' ) );
		console.log();
		this.spawnCommandSync( 'grunt', [ 'import' ] );
		done();
	},
	allowRun: function(){}
});
<commit_msg>use direct run loop call to import DB<commit_after>var _ = require( 'lodash' );
var path = require( 'path' );
var Base = require( '../../lib/base' );
var chalk = require( 'chalk' );

module.exports = Base.extend({
	pullMap: {
		'uploads': '_getUploads',
		'db': '_getSQL',
	},
	_initialize: function() {
		this.addRunMethod(
			'pull',
			this._doPull,
			'default'
		);
	},
	_doPull: function( done ) {
		var pulls = _.remove( this.arguments.map( this._getPull, this ) );

		if ( 1 > pulls.length ) {
			return done();
		}

		this.multiDownload( pulls )
			.then( done )
			.catch( function( err ){
				this.log( err.message );
				process.exit( 0 );
			}.bind( this ));
	},
	_getPull: function( pull ) {
		if ( this.pullMap[ pull ] ) {
			return this[ this.pullMap[ pull ] ]();
		} else {
			return false;
		}
	},
	_getUploads: function() {
		var uploads = false;
		if ( this.install.uploads ) {
			if ( 'string' === typeof this.install.uploads ) {
				uploads = { location: this.install.uploads };
			} else {
				uploads = _.clone( this.install.uploads );
			}
			uploads.dest = this.getAppPath( 'content-path', 'app', 'uploads' );
			uploads.opts = uploads.opts || {};
			uploads.opts.extract = { strip: 1 };
		}
		return uploads;
	},
	_getSQL: function() {
		var database = false;
		if ( this.install.database ) {
			if ( 'string' ===  typeof this.install.database ) {
				database = { location: this.install.database };
			} else {
				database = _.clone( this.install.database );
			}
			database.dest = path.join( 'config', 'data' );
		}
		if ( this.isRoot ) {
			this.env.runLoop.add(
				'install',
				this._import.bind( this ),
				{ once: 'import', run: false }
			);
		}
		return database;
	},
	_import: function( done ){
		console.log();
		console.log( chalk.yellow( 'Attempting to import your database.' ) );
		console.log();
		this.spawnCommandSync( 'grunt', [ 'import' ] );
		done();
	},
	allowRun: function(){}
});
<|endoftext|>


<commit_before>'use strict';
const Generator = require('yeoman-generator');
const fs = require('fs');

class RootGenerator extends Generator {

  /*
  constructor(args, opts) {
    super(args, opts);
  }
  */

  writing() {
    /* Some base functionality needs to be overwritten, so we force yeoman to do
     * so. This is not the nicest thing to do, but since this changes are needed
     * it does not make sense to give the user a choice.
     */
    this.conflicter.force = true;

    // Copy the store
    this.fs.copy(
      this.templatePath('store.js'),
      this.destinationPath('src/stores/index.js')
    );

    // Copy the root reducer
    this.fs.copy(
      this.templatePath('reducer.js'),
      this.destinationPath('src/reducers/index.js')
    );

    // Copy the actions const template
    this.fs.copy(
      this.templatePath('./action/const.js'),
      this.destinationPath('src/actions/const.js')
    );

    // Copy the actions export template
    this.fs.copy(
      this.templatePath('./action/index.js'),
      this.destinationPath('src/actions/index.js')
    );

    // Copy the entry point over the original entry point
    this.fs.copy(
      this.templatePath('client.js'),
      this.destinationPath('src/client.js')
    );

    // Copy the app container
    this.fs.copy(
      this.templatePath('App.js'),
      this.destinationPath('src/containers/App.js')
    );

    // Copy the adapted eslintrc
    this.fs.copy(
      this.templatePath('eslintrc'),
      this.destinationPath('.eslintrc')
    );
  }
};

module.exports = RootGenerator;
<commit_msg>Removed constructor, we can use the default one<commit_after>'use strict';
const Generator = require('yeoman-generator');
const fs = require('fs');

class RootGenerator extends Generator {
  writing() {
    /* Some base functionality needs to be overwritten, so we force yeoman to do
     * so. This is not the nicest thing to do, but since this changes are needed
     * it does not make sense to give the user a choice.
     */
    this.conflicter.force = true;

    // Copy the store
    this.fs.copy(
      this.templatePath('store.js'),
      this.destinationPath('src/stores/index.js')
    );

    // Copy the root reducer
    this.fs.copy(
      this.templatePath('reducer.js'),
      this.destinationPath('src/reducers/index.js')
    );

    // Copy the actions const template
    this.fs.copy(
      this.templatePath('./action/const.js'),
      this.destinationPath('src/actions/const.js')
    );

    // Copy the actions export template
    this.fs.copy(
      this.templatePath('./action/index.js'),
      this.destinationPath('src/actions/index.js')
    );

    // Copy the entry point over the original entry point
    this.fs.copy(
      this.templatePath('client.js'),
      this.destinationPath('src/client.js')
    );

    // Copy the app container
    this.fs.copy(
      this.templatePath('App.js'),
      this.destinationPath('src/containers/App.js')
    );

    // Copy the adapted eslintrc
    this.fs.copy(
      this.templatePath('eslintrc'),
      this.destinationPath('.eslintrc')
    );
  }
};

module.exports = RootGenerator;
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var filename = require("../util/filename");
var Q = require('q');
var writeFile = Q.denodeify(fs.writeFile);
var mkdirs = Q.denodeify(require("fs-extra").mkdirs);
var striptags = require("striptags");
var bitDocsHelpers = require('bit-docs-generate-html/build/make_default_helpers');

/**
 * @function bitDocs.generators.searchMap.searchMap
 * @parent bitDocs.generators.searchMap.methods
 *
 * Writes out a simplified [documentjs.process.docMap docMap] to be used for searching.
 *
 * @signature `searchMap(docMap, siteConfig)`
 *
 * @param {documentjs.process.docMap} docMap
 * @param {Object} siteConfig
 * @return {Promise} Resolves when searchMap has been written.
 */
module.exports = function(docMap, siteConfig) {
	return new Promise(function(resolve, reject) {
		var searchMap = {};
		var name;
		for (name in docMap) {
			if (docMap.hasOwnProperty(name)) {
				var docObj = docMap[name];
				// If there is no body, it's likely we don't want to index it
				if(docObj.description || docObj.signatures || docObj.params || docObj.return || docObj.options){
					var helpers = bitDocsHelpers(docMap, siteConfig, function(){
						return docObj;
					}, {});

					var description = helpers.makeHtml(docObj.description);
					description = helpers.makeLinks(description);
					description = striptags(description,
						// Allowed tags
						['a', 'em', 'code']
					);

					var searchObj = {
						name: docObj.name,
						title: docObj.title,
						description: description,
						url: filename(docObj, siteConfig)
					};
					searchMap[name] = searchObj;
				}
			}
		}

		var dest = path.join(siteConfig.dest, 'searchMap.json');

		mkdirs(siteConfig.dest).then(function(){
			writeFile(dest, JSON.stringify(searchMap)).then(function(){
				resolve(searchMap);
			}, reject);
		}, reject);
	});
};<commit_msg>Fixed check for signature content<commit_after>var fs = require('fs');
var path = require('path');
var filename = require("../util/filename");
var Q = require('q');
var writeFile = Q.denodeify(fs.writeFile);
var mkdirs = Q.denodeify(require("fs-extra").mkdirs);
var striptags = require("striptags");
var bitDocsHelpers = require('bit-docs-generate-html/build/make_default_helpers');

/**
 * @function bitDocs.generators.searchMap.searchMap
 * @parent bitDocs.generators.searchMap.methods
 *
 * Writes out a simplified [documentjs.process.docMap docMap] to be used for searching.
 *
 * @signature `searchMap(docMap, siteConfig)`
 *
 * @param {documentjs.process.docMap} docMap
 * @param {Object} siteConfig
 * @return {Promise} Resolves when searchMap has been written.
 */
module.exports = function(docMap, siteConfig) {
	return new Promise(function(resolve, reject) {
		var searchMap = {};
		var name;
		for (name in docMap) {
			if (docMap.hasOwnProperty(name)) {
				var docObj = docMap[name];
				var signaturesHaveContent = docObj.signatures && docObj.signatures.some(function(signature){
					return signature.params || signature.return || signature.options;
				});
				// If there is no body, it's likely we don't want to index it
				if(docObj.description || signaturesHaveContent){
					var helpers = bitDocsHelpers(docMap, siteConfig, function(){
						return docObj;
					}, {});

					var description = helpers.makeHtml(docObj.description);
					description = helpers.makeLinks(description);
					description = striptags(description,
						// Allowed tags
						['a', 'em', 'code']
					);

					var searchObj = {
						name: docObj.name,
						title: docObj.title,
						description: description,
						url: filename(docObj, siteConfig)
					};
					searchMap[name] = searchObj;
				}
			}
		}

		var dest = path.join(siteConfig.dest, 'searchMap.json');

		mkdirs(siteConfig.dest).then(function(){
			writeFile(dest, JSON.stringify(searchMap)).then(function(){
				resolve(searchMap);
			}, reject);
		}, reject);
	});
};<|endoftext|>


<commit_before>import fileSaver from 'filesaverjs';
import { observer } from 'binary-common-utils/lib/observer';
import config from '../../../common/const';
import { translator } from '../../../common/translator';
import { bot } from '../../bot';
import { addPurchaseOptions, getBlockByType, isMainBlock, findTopParentBlock } from './utils';
import blocks from './blocks';

export default class _Blockly {
  constructor() {
    this.blocksXmlStr = '';
    this.generatedJs = '';
    this.addBlocklyTranslation();
    this.initPromise = new Promise((resolve) => {
      $.get('xml/toolbox.xml', (toolbox) => {
        blocks();
        const workspace = Blockly.inject('blocklyDiv', {
          media: 'js/blockly/media/',
          toolbox: this.xmlToStr(translator.translateXml($.parseXML(
            this.marketsToXml(toolbox.getElementsByTagName('xml')[0])
          ))),
          zoom: {
            wheel: false,
          },
          trashcan: false,
          collapse: false,
        });
        $.get('xml/main.xml', (main) => {
          this.blocksXmlStr = Blockly.Xml.domToPrettyText(main);
          Blockly.Xml.domToWorkspace(main.getElementsByTagName('xml')[0], workspace);
          this.disableDeleteForMainBlocks();
          this.overrideBlocklyDefaultShape();
          this.zoomOnPlusMinus();
          Blockly.mainWorkspace.clearUndo();
          addPurchaseOptions();
          resolve();
        });
      });
    });
  }
  zoomOnPlusMinus(zoomIn) {
    const metrics = Blockly.mainWorkspace.getMetrics();
    if (zoomIn) {
      Blockly.mainWorkspace.zoom(metrics.viewWidth / 2, metrics.viewHeight / 2, 1);
    } else {
      Blockly.mainWorkspace.zoom(metrics.viewWidth / 2, metrics.viewHeight / 2, -1);
    }
  }
  createXmlTag(obj) {
    let xmlStr = '<category name="Markets" colour="#2a3052" i18n-text="Markets">\n';
    for (const market of Object.keys(obj)) {
      xmlStr += `\t<category name="${obj[market].name}" colour="#2a3052">`;
      for (const submarket of Object.keys(obj[market].submarkets)) {
        xmlStr += `\t\t<category name="${
        obj[market].submarkets[submarket].name}" colour="#2a3052">`;
        for (const symbol of Object.keys(obj[market].submarkets[submarket].symbols)) {
          xmlStr += `\t\t\t<block type="${symbol.toLowerCase()}"></block>`;
        }
        xmlStr += '\t\t</category>\n';
      }
      xmlStr += '\t</category>\n';
    }
    xmlStr += '</category>\n';
    return xmlStr;
  }
  xmlToStr(xml) {
    const serializer = new XMLSerializer();
    return serializer.serializeToString(xml);
  }
  marketsToXml(xml) {
    const xmlStr = this.xmlToStr(xml);
    const marketXml = this.createXmlTag(
      bot.symbol.activeSymbols.getMarkets(), bot.symbol.assetIndex);
    return xmlStr.replace('<!--Markets-->', marketXml);
  }
  disableDeleteForMainBlocks() {
    for (const blockType of config.mainBlocks) {
      getBlockByType(blockType)
        .setDeletable(false);
    }
  }
  overrideBlocklyDefaultShape() {
    Blockly.Blocks.text.newQuote_ = (open) => { // eslint-disable-line no-underscore-dangle
      let file;
      if (open === this.RTL) {
        file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAYAAAAGuM1UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAFpJREFUeNpiZGBg+M+ACRyh9H50CSYGEsEg1AACDlB8HxoAIKwAxAJIcu+h4u+RNcEUz0czMAFJroEBKfiQTUcG95FMF2BBUnAAiA8C8QM05z6A4o1A/AEgwACTSBqO/l02SwAAAABJRU5ErkJggg=='; // eslint-disable-line max-len
      } else {
        file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAYAAAAGuM1UAAAAAXNSR0IArs4c6QAAActpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgSW1hZ2VSZWFkeTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KKS7NPQAAAHFJREFUGBljYICAAiC1H4odIEJwsgHIgskpgEQFgPg9EP8H4vtAjAwUgByQOAjvB2IwaACSMMEEsAiCmI8k5wASZgRikOkgWz4AcSAQg8AFIAaJ3QdxgOABECeCGCANINPRgSNUYD+6BBO6ACH+INQAAKsvFws0VtvEAAAAAElFTkSuQmCC'; // eslint-disable-line max-len
      }
      return new Blockly.FieldImage(file, 12, 12, '"');
    };
    Blockly.Blocks.texts.HUE = '#dedede';
    Blockly.Blocks.math.HUE = '#dedede';
    Blockly.Blocks.logic.HUE = '#dedede';
    Blockly.Blocks.lists.HUE = '#dedede';
    Blockly.Blocks.variables.HUE = '#dedede';
    Blockly.Blocks.procedures.HUE = '#dedede';
    this.setBlockColors();
  }
  addMissingMainBlocks() {
    for (const mainBlock of config.mainBlocks) {
      if (!getBlockByType(mainBlock)) {
        const block = Blockly.mainWorkspace.newBlock(mainBlock);
        block.initSvg();
        block.render();
        this.setBlockColors();
        block.setDeletable(false);
      }
    }
  }
  reconfigureBlocklyAfterLoad() {
    this.addMissingMainBlocks();
    Blockly.mainWorkspace.clearUndo();
    this.setBlockColors();
    addPurchaseOptions();
  }
  loadBlocks(str) {
    if (str) {
      this.blocksXmlStr = str;
    }
    try {
      Blockly.mainWorkspace.clear();
      const xml = Blockly.Xml.textToDom(this.blocksXmlStr);
      Blockly.Xml.domToWorkspace(xml, Blockly.mainWorkspace);
      this.reconfigureBlocklyAfterLoad();
      observer.emit('ui.log.success',
        translator.translateText('Blocks are loaded successfully'));
    } catch (e) {
      if (e.name === 'BlocklyError') {
        // pass
      } else {
        throw e;
      }
    }
  }
  selectBlockByText(text) {
    let returnVal;
    $('.blocklyText').each(function each() {
      if ($(this).text().indexOf(text) >= 0) {
        returnVal = $(this).parent()[0];
      }
    });
    return returnVal;
  }
  setBlockColors() {
    for (const blockType of config.mainBlocks) {
      const block = getBlockByType(blockType);
      if (block) {
        block.getField().getSvgRoot()
          .style.setProperty('fill', 'white', 'important');
      }
    }
  }
  saveXml() {
    const xmlDom = Blockly.Xml.workspaceToDom(Blockly.mainWorkspace);
    for (const field of Array.prototype.slice.apply(xmlDom.getElementsByTagName('field'))) {
      if (field.getAttribute('name') === 'ACCOUNT_LIST') {
        if (field.childNodes.length >= 1) {
          field.childNodes[0].nodeValue = '';
        }
      }
    }
    const xmlText = Blockly.Xml.domToPrettyText(xmlDom);
    const filename = `binary-bot${parseInt(new Date().getTime() / 1000, 10)}.xml`;
    const blob = new Blob([xmlText], {
      type: 'text/xml;charset=utf-8',
    });
    fileSaver.saveAs(blob, filename);
  }
  deleteStrayBlocks() {
    const topBlocks = Blockly.mainWorkspace.getTopBlocks();
    for (const block of topBlocks) {
      if (!isMainBlock(block.type)
        && block !== findTopParentBlock(getBlockByType('trade'))
        && block.type.indexOf('procedures_def') < 0
        && block.type !== 'block_holder') {
        block.dispose();
      }
    }
  }
  run() {
    let code;
    try {
      window.LoopTrap = 1000;
      Blockly.JavaScript
        .INFINITE_LOOP_TRAP = 'if (--window.LoopTrap == 0) throw "Infinite loop.";\n';
      this.deleteStrayBlocks();
      this.blocksXmlStr = Blockly.Xml.domToPrettyText(
        Blockly.Xml.workspaceToDom(Blockly.mainWorkspace));
      code = `
        ${Blockly.JavaScript.workspaceToCode(Blockly.mainWorkspace)}
        try {
          if (typeof trade !== 'undefined') {
            trade();
          }
        } catch (e) {
          if (e.name === 'RuntimeError') {
            // pass
          } else {
            throw e;
          }
        }
      `;
      Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
      this.generatedJs = code;
    } catch (e) {
      if (e.name === 'BlocklyError') {
        // pass
      } else {
        throw e;
      }
    }
    if (code) {
      eval(code); // eslint-disable-line no-eval
      $('#summaryPanel')
        .show();
    }
  }
  addBlocklyTranslation() {
    $.ajaxPrefilter((options) => {
      options.async = true; // eslint-disable-line no-param-reassign
    });
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = `js/blockly/msg/js/${translator.getLanguage()}.js`;
    $('body').append(script);
  }
  undo() {
    Blockly.mainWorkspace.undo();
    this.setBlockColors();
  }
  redo() {
    Blockly.mainWorkspace.undo(true);
    this.setBlockColors();
  }
}
<commit_msg>Increased the infinite loop counter<commit_after>import fileSaver from 'filesaverjs';
import { observer } from 'binary-common-utils/lib/observer';
import config from '../../../common/const';
import { translator } from '../../../common/translator';
import { bot } from '../../bot';
import { addPurchaseOptions, getBlockByType, isMainBlock, findTopParentBlock } from './utils';
import blocks from './blocks';

export default class _Blockly {
  constructor() {
    this.blocksXmlStr = '';
    this.generatedJs = '';
    this.addBlocklyTranslation();
    this.initPromise = new Promise((resolve) => {
      $.get('xml/toolbox.xml', (toolbox) => {
        blocks();
        const workspace = Blockly.inject('blocklyDiv', {
          media: 'js/blockly/media/',
          toolbox: this.xmlToStr(translator.translateXml($.parseXML(
            this.marketsToXml(toolbox.getElementsByTagName('xml')[0])
          ))),
          zoom: {
            wheel: false,
          },
          trashcan: false,
          collapse: false,
        });
        $.get('xml/main.xml', (main) => {
          this.blocksXmlStr = Blockly.Xml.domToPrettyText(main);
          Blockly.Xml.domToWorkspace(main.getElementsByTagName('xml')[0], workspace);
          this.disableDeleteForMainBlocks();
          this.overrideBlocklyDefaultShape();
          this.zoomOnPlusMinus();
          Blockly.mainWorkspace.clearUndo();
          addPurchaseOptions();
          resolve();
        });
      });
    });
  }
  zoomOnPlusMinus(zoomIn) {
    const metrics = Blockly.mainWorkspace.getMetrics();
    if (zoomIn) {
      Blockly.mainWorkspace.zoom(metrics.viewWidth / 2, metrics.viewHeight / 2, 1);
    } else {
      Blockly.mainWorkspace.zoom(metrics.viewWidth / 2, metrics.viewHeight / 2, -1);
    }
  }
  createXmlTag(obj) {
    let xmlStr = '<category name="Markets" colour="#2a3052" i18n-text="Markets">\n';
    for (const market of Object.keys(obj)) {
      xmlStr += `\t<category name="${obj[market].name}" colour="#2a3052">`;
      for (const submarket of Object.keys(obj[market].submarkets)) {
        xmlStr += `\t\t<category name="${
        obj[market].submarkets[submarket].name}" colour="#2a3052">`;
        for (const symbol of Object.keys(obj[market].submarkets[submarket].symbols)) {
          xmlStr += `\t\t\t<block type="${symbol.toLowerCase()}"></block>`;
        }
        xmlStr += '\t\t</category>\n';
      }
      xmlStr += '\t</category>\n';
    }
    xmlStr += '</category>\n';
    return xmlStr;
  }
  xmlToStr(xml) {
    const serializer = new XMLSerializer();
    return serializer.serializeToString(xml);
  }
  marketsToXml(xml) {
    const xmlStr = this.xmlToStr(xml);
    const marketXml = this.createXmlTag(
      bot.symbol.activeSymbols.getMarkets(), bot.symbol.assetIndex);
    return xmlStr.replace('<!--Markets-->', marketXml);
  }
  disableDeleteForMainBlocks() {
    for (const blockType of config.mainBlocks) {
      getBlockByType(blockType)
        .setDeletable(false);
    }
  }
  overrideBlocklyDefaultShape() {
    Blockly.Blocks.text.newQuote_ = (open) => { // eslint-disable-line no-underscore-dangle
      let file;
      if (open === this.RTL) {
        file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAYAAAAGuM1UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAFpJREFUeNpiZGBg+M+ACRyh9H50CSYGEsEg1AACDlB8HxoAIKwAxAJIcu+h4u+RNcEUz0czMAFJroEBKfiQTUcG95FMF2BBUnAAiA8C8QM05z6A4o1A/AEgwACTSBqO/l02SwAAAABJRU5ErkJggg=='; // eslint-disable-line max-len
      } else {
        file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAYAAAAGuM1UAAAAAXNSR0IArs4c6QAAActpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgSW1hZ2VSZWFkeTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KKS7NPQAAAHFJREFUGBljYICAAiC1H4odIEJwsgHIgskpgEQFgPg9EP8H4vtAjAwUgByQOAjvB2IwaACSMMEEsAiCmI8k5wASZgRikOkgWz4AcSAQg8AFIAaJ3QdxgOABECeCGCANINPRgSNUYD+6BBO6ACH+INQAAKsvFws0VtvEAAAAAElFTkSuQmCC'; // eslint-disable-line max-len
      }
      return new Blockly.FieldImage(file, 12, 12, '"');
    };
    Blockly.Blocks.texts.HUE = '#dedede';
    Blockly.Blocks.math.HUE = '#dedede';
    Blockly.Blocks.logic.HUE = '#dedede';
    Blockly.Blocks.lists.HUE = '#dedede';
    Blockly.Blocks.variables.HUE = '#dedede';
    Blockly.Blocks.procedures.HUE = '#dedede';
    this.setBlockColors();
  }
  addMissingMainBlocks() {
    for (const mainBlock of config.mainBlocks) {
      if (!getBlockByType(mainBlock)) {
        const block = Blockly.mainWorkspace.newBlock(mainBlock);
        block.initSvg();
        block.render();
        this.setBlockColors();
        block.setDeletable(false);
      }
    }
  }
  reconfigureBlocklyAfterLoad() {
    this.addMissingMainBlocks();
    Blockly.mainWorkspace.clearUndo();
    this.setBlockColors();
    addPurchaseOptions();
  }
  loadBlocks(str) {
    if (str) {
      this.blocksXmlStr = str;
    }
    try {
      Blockly.mainWorkspace.clear();
      const xml = Blockly.Xml.textToDom(this.blocksXmlStr);
      Blockly.Xml.domToWorkspace(xml, Blockly.mainWorkspace);
      this.reconfigureBlocklyAfterLoad();
      observer.emit('ui.log.success',
        translator.translateText('Blocks are loaded successfully'));
    } catch (e) {
      if (e.name === 'BlocklyError') {
        // pass
      } else {
        throw e;
      }
    }
  }
  selectBlockByText(text) {
    let returnVal;
    $('.blocklyText').each(function each() {
      if ($(this).text().indexOf(text) >= 0) {
        returnVal = $(this).parent()[0];
      }
    });
    return returnVal;
  }
  setBlockColors() {
    for (const blockType of config.mainBlocks) {
      const block = getBlockByType(blockType);
      if (block) {
        block.getField().getSvgRoot()
          .style.setProperty('fill', 'white', 'important');
      }
    }
  }
  saveXml() {
    const xmlDom = Blockly.Xml.workspaceToDom(Blockly.mainWorkspace);
    for (const field of Array.prototype.slice.apply(xmlDom.getElementsByTagName('field'))) {
      if (field.getAttribute('name') === 'ACCOUNT_LIST') {
        if (field.childNodes.length >= 1) {
          field.childNodes[0].nodeValue = '';
        }
      }
    }
    const xmlText = Blockly.Xml.domToPrettyText(xmlDom);
    const filename = `binary-bot${parseInt(new Date().getTime() / 1000, 10)}.xml`;
    const blob = new Blob([xmlText], {
      type: 'text/xml;charset=utf-8',
    });
    fileSaver.saveAs(blob, filename);
  }
  deleteStrayBlocks() {
    const topBlocks = Blockly.mainWorkspace.getTopBlocks();
    for (const block of topBlocks) {
      if (!isMainBlock(block.type)
        && block !== findTopParentBlock(getBlockByType('trade'))
        && block.type.indexOf('procedures_def') < 0
        && block.type !== 'block_holder') {
        block.dispose();
      }
    }
  }
  run() {
    let code;
    try {
      window.LoopTrap = 99999999999;
      Blockly.JavaScript
        .INFINITE_LOOP_TRAP = 'if (--window.LoopTrap == 0) throw "Infinite loop.";\n';
      this.deleteStrayBlocks();
      this.blocksXmlStr = Blockly.Xml.domToPrettyText(
        Blockly.Xml.workspaceToDom(Blockly.mainWorkspace));
      code = `
        ${Blockly.JavaScript.workspaceToCode(Blockly.mainWorkspace)}
        try {
          if (typeof trade !== 'undefined') {
            trade();
          }
        } catch (e) {
          if (e.name === 'RuntimeError') {
            // pass
          } else {
            throw e;
          }
        }
      `;
      Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
      this.generatedJs = code;
    } catch (e) {
      if (e.name === 'BlocklyError') {
        // pass
      } else {
        throw e;
      }
    }
    if (code) {
      eval(code); // eslint-disable-line no-eval
      $('#summaryPanel')
        .show();
    }
  }
  addBlocklyTranslation() {
    $.ajaxPrefilter((options) => {
      options.async = true; // eslint-disable-line no-param-reassign
    });
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = `js/blockly/msg/js/${translator.getLanguage()}.js`;
    $('body').append(script);
  }
  undo() {
    Blockly.mainWorkspace.undo();
    this.setBlockColors();
  }
  redo() {
    Blockly.mainWorkspace.undo(true);
    this.setBlockColors();
  }
}
<|endoftext|>


<commit_before>import File from './file';

function moduleNames(object) {
  if (object === undefined) return new Set();

  const modules = new Set();

  Object.keys(object).forEach(k => {
    const v = object[k];
    if (typeof v === 'string') {
      modules.add(v);
    } else if (Array.isArray(v)) {
      v.forEach(e => {
        if (typeof e === 'string') {
          modules.add(e);
        }
      });
    }
  });

  return modules;
}

export default class Package extends File {
  static matchesFileName(name) {
    return name.match(/^package\.json$/);
  }

  optionalDevModules(modules = new Set()) {
    return new Set(['cracks', 'dont-crack'].filter(m => modules.has(m)));
  }

  async usedDevModules(content) {
    content = await content;

    const pkg = content.length === 0 ? {} : JSON.parse(content);

    return moduleNames(pkg.release);
  }

  async templateRepo(context) {
    const content = await this.originalContent(context, {
      ignoreMissing: true
    });
    const pkg = JSON.parse(content);
    if (pkg.template !== undefined && pkg.template.repository !== undefined) {
      const m = pkg.template.repository.url.match(/github.com\/(.*)\.git$/);
      return m[1];
    }

    return undefined;
  }

  async mergeContent(context, original, templateContent) {
    const originalLastChar = original[original.length - 1];

    let target =
      original === undefined || original === '' ? {} : JSON.parse(original);
    const template = JSON.parse(templateContent);
    let messages = [];
    const properties = context.properties;

    if (target.name === undefined || target.name === '') {
      const m = context.targetRepo.name.match(/^([^\/]+)\/(.*)/);
      target.name = m ? m[2] : context.targetRepo.name;
    }

    if (target.module !== undefined && !target.module.match(/\{\{module\}\}/)) {
      properties.module = target.module;
    }

    properties.main =
      target.main && !target.main.match(/\{\{main\}\}/)
        ? target.main
        : 'dist/index.js';

    const githubURL = `git+https://github.com/${properties.user}/${target.name}.git`;
    const githubURLAlternative = `git+https://github.com/${properties.user}/node-${target.name}.git`;

    let repoName = target.name;

    if (
      target.repository === undefined ||
      (target.repository.url !== githubURL &&
        target.repository.url !== githubURLAlternative)
    ) {
      target.repository = {
        type: 'git',
        url: githubURL
      };
      messages.push(`chore(package): correct github url`);
    }

    if (
      target.repository !== undefined &&
      githubURLAlternative === target.repository.url
    ) {
      repoName = `node-${target.name}`;
    }

    const bugsURL = `https://github.com/${properties.user}/${repoName}/issues`;

    if (target.bugs === undefined || target.bugs.url !== bugsURL) {
      target.bugs = {
        url: bugsURL
      };
      messages.push(`chore(package): correct bugs url`);
    }

    const homepageURL = `https://github.com/${properties.user}/${repoName}#readme`;

    if (target.homepage === undefined || target.homepage !== homepageURL) {
      target.homepage = homepageURL;
      messages.push(`chore(package): correct hompage url`);
    }

    let buildOutput;
    const extraBuilds = {};

    if (target.scripts !== undefined) {
      Object.keys(target.scripts).forEach(key => {
        const script = target.scripts[key];
        const ma = script.match(/--output=([^\s]+)/);
        if (ma) {
          buildOutput = ma[1];
        }

        if (template.scripts !== undefined && key !== 'semantic-release') {
          const templateScript = template.scripts[key];
          if (templateScript !== undefined) {
            const mb = script.match(/&&\s*(.+)$/);
            if (mb && !templateScript.includes(mb[1])) {
              extraBuilds[key] = mb[1];
            }
          }
        }
      });
    }

    const usedDevModules = await context.usedDevModules();
    const optionalDevModules = context.optionalDevModules(usedDevModules);

    const deepPropeties = {
      scripts: {},
      devDependencies: {},
      engines: {}
    };

    Object.keys(deepPropeties).forEach(category => {
      if (target[category] === undefined) {
        target[category] = {};
      }

      if (template[category] !== undefined) {
        Object.keys(template[category]).forEach(d => {
          if (template[category][d] === '-') {
            if (target[category][d] !== undefined) {
              messages.push(
                `chore(${category}): remove ${d}@${target[category][d]}`
              );
              delete target[category][d];
            }
          } else {
            const tp = context.expand(template[category][d]);

            if (tp !== target[category][d]) {
              messages.push(
                target[category][d] === undefined
                  ? `chore(${category}): add ${d}@${tp} from template`
                  : `chore(${category}): update ${d}@${tp} from template`
              );
              target[category][d] = tp;
            }
          }
        });
      }
    });

    Object.keys(template).forEach(p => {
      if (p !== 'template') {
        if (target[p] === undefined) {
          target[p] = template[p];
        }
      }
    });

    if (target.scripts.prepare) {
      if (buildOutput !== undefined) {
        target.scripts.prepare = target.scripts.prepare.replace(
          /--output=([^\s]+)/,
          `--output=${buildOutput}`
        );
      }
    }

    Object.keys(extraBuilds).forEach(key => {
      target.scripts[key] += ` && ${extraBuilds[key]}`;
    });

    if (target.module === '{{module}}') {
      delete target.module;
    }

    if (
      target.contributors !== undefined &&
      target.author !== undefined &&
      target.author.name !== undefined
    ) {
      const m = target.author.name.match(/(^[^<]+)<([^>]+)>/);
      if (m !== undefined) {
        const name = String(m[1]).replace(/^\s+|\s+$/g, '');
        const email = m[2];

        if (
          target.contributors.find(c => c.name === name && c.email === email)
        ) {
          delete target.author;
        }
      }
    }

    if (
      target.template === undefined ||
      target.template.repository === undefined ||
      target.template.repository.url !==
        `https://github.com/${context.templateRepo.name}.git`
    ) {
      messages.push('chore(package): set template repo');

      target.template = {
        repository: {
          url: `https://github.com/${context.templateRepo.name}.git`
        }
      };
    }

    const toBeDeletedModules = Array.from(
      context.optionalDevModules(new Set(Object.keys(target.devDependencies)))
    ).filter(m => !usedDevModules.has(m));

    /*
    console.log(`modules: ${Object.keys(target.devDependencies)}`);
    console.log(`used modules: ${Array.from(usedDevModules)}`);
    console.log(
      `optional modules: ${Array.from(
        context.optionalDevModules(new Set(Object.keys(target.devDependencies)))
      )}`
    );
    console.log(`toBeDeletedModules: ${Array.from(toBeDeletedModules)}`);
*/

    toBeDeletedModules.forEach(d => {
      messages = messages.filter(
        m => !m.startsWith(`chore(devDependencies): add ${d}@`)
      );
      delete target.devDependencies[d];
    });

    target = deleter(target, template, messages, []);

    if (target.keywords !== undefined) {
      delete target.keywords['npm-package-template'];
    }

    if (
      template.template !== undefined &&
      template.template.keywords !== undefined
    ) {
      Object.keys(template.template.keywords).forEach(r =>
        addKeyword(
          target,
          new RegExp(r),
          template.template.keywords[r],
          messages
        )
      );
    }

    removeKeyword(target, ['null', null, undefined], messages);

    if (messages.length === 0) {
      messages.push('chore: update package.json from template');
    }

    let newContent = JSON.stringify(context.expand(target), undefined, 2);
    const lastChar = newContent[newContent.length - 1];

    // keep trailing newline
    if (originalLastChar === '\n' && lastChar === '}') {
      newContent += '\n';
    }

    return {
      content: newContent,
      messages,
      changed: original !== newContent
    };
  }
}

function deleter(object, reference, messages, path) {
  if (
    typeof object === 'string' ||
    object instanceof String ||
    object === true ||
    object === false ||
    object === undefined ||
    object === null ||
    typeof object === 'number' ||
    object instanceof Number
  ) {
    return object;
  }

  if (Array.isArray(object)) {
    return object;
  }

  Object.keys(reference).forEach(key => {
    path.push(key);

    if (reference[key] === '--delete--' && object[key] !== undefined) {
      if (object[key] !== '--delete--') {
        messages.push(`chore(npm): delete ${path.join('.')}`);
      }
      delete object[key];
    } else {
      object[key] = deleter(object[key], reference[key], messages, path);
    }
    path.pop();
  });

  return object;
}

function removeKeyword(pkg, keywords, messages) {
  if (pkg.keywords !== undefined) {
    keywords.forEach(keyword => {
      if (pkg.keywords.find(k => k === keyword)) {
        messages.push(`docs(package): remove keyword ${keyword}`);
        pkg.keywords = pkg.keywords.filter(k => k !== keyword);
      }
    });

    if (pkg.keywords[0] === null || pkg.keywords[0] === undefined) {
      messages.push(`docs(package): remove keyword null`);
      pkg.keywords = [];
    }
  }
}

function addKeyword(pkg, regex, keyword, messages) {
  if (keyword === undefined || keyword === null || keyword === 'null') {
    return;
  }

  if (pkg.name.match(regex)) {
    if (pkg.keywords === undefined) {
      pkg.keywords = [];
    }
    if (!pkg.keywords.find(k => k === keyword)) {
      messages.push(`docs(package): add keyword ${keyword}`);
      pkg.keywords.push(keyword);
    }
  }
}
<commit_msg>fix(package): deep delete into array too<commit_after>import File from './file';

function moduleNames(object) {
  if (object === undefined) return new Set();

  const modules = new Set();

  Object.keys(object).forEach(k => {
    const v = object[k];
    if (typeof v === 'string') {
      modules.add(v);
    } else if (Array.isArray(v)) {
      v.forEach(e => {
        if (typeof e === 'string') {
          modules.add(e);
        }
      });
    }
  });

  return modules;
}

export default class Package extends File {
  static matchesFileName(name) {
    return name.match(/^package\.json$/);
  }

  optionalDevModules(modules = new Set()) {
    return new Set(['cracks', 'dont-crack'].filter(m => modules.has(m)));
  }

  async usedDevModules(content) {
    content = await content;

    const pkg = content.length === 0 ? {} : JSON.parse(content);

    return moduleNames(pkg.release);
  }

  async templateRepo(context) {
    const content = await this.originalContent(context, {
      ignoreMissing: true
    });
    const pkg = JSON.parse(content);
    if (pkg.template !== undefined && pkg.template.repository !== undefined) {
      const m = pkg.template.repository.url.match(/github.com\/(.*)\.git$/);
      return m[1];
    }

    return undefined;
  }

  async mergeContent(context, original, templateContent) {
    const originalLastChar = original[original.length - 1];

    let target =
      original === undefined || original === '' ? {} : JSON.parse(original);
    const template = JSON.parse(templateContent);
    let messages = [];
    const properties = context.properties;

    if (target.name === undefined || target.name === '') {
      const m = context.targetRepo.name.match(/^([^\/]+)\/(.*)/);
      target.name = m ? m[2] : context.targetRepo.name;
    }

    if (target.module !== undefined && !target.module.match(/\{\{module\}\}/)) {
      properties.module = target.module;
    }

    properties.main =
      target.main && !target.main.match(/\{\{main\}\}/)
        ? target.main
        : 'dist/index.js';

    const githubURL = `git+https://github.com/${properties.user}/${target.name}.git`;
    const githubURLAlternative = `git+https://github.com/${properties.user}/node-${target.name}.git`;

    let repoName = target.name;

    if (
      target.repository === undefined ||
      (target.repository.url !== githubURL &&
        target.repository.url !== githubURLAlternative)
    ) {
      target.repository = {
        type: 'git',
        url: githubURL
      };
      messages.push(`chore(package): correct github url`);
    }

    if (
      target.repository !== undefined &&
      githubURLAlternative === target.repository.url
    ) {
      repoName = `node-${target.name}`;
    }

    const bugsURL = `https://github.com/${properties.user}/${repoName}/issues`;

    if (target.bugs === undefined || target.bugs.url !== bugsURL) {
      target.bugs = {
        url: bugsURL
      };
      messages.push(`chore(package): correct bugs url`);
    }

    const homepageURL = `https://github.com/${properties.user}/${repoName}#readme`;

    if (target.homepage === undefined || target.homepage !== homepageURL) {
      target.homepage = homepageURL;
      messages.push(`chore(package): correct hompage url`);
    }

    let buildOutput;
    const extraBuilds = {};

    if (target.scripts !== undefined) {
      Object.keys(target.scripts).forEach(key => {
        const script = target.scripts[key];
        const ma = script.match(/--output=([^\s]+)/);
        if (ma) {
          buildOutput = ma[1];
        }

        if (template.scripts !== undefined && key !== 'semantic-release') {
          const templateScript = template.scripts[key];
          if (templateScript !== undefined) {
            const mb = script.match(/&&\s*(.+)$/);
            if (mb && !templateScript.includes(mb[1])) {
              extraBuilds[key] = mb[1];
            }
          }
        }
      });
    }

    const usedDevModules = await context.usedDevModules();
    const optionalDevModules = context.optionalDevModules(usedDevModules);

    const deepPropeties = {
      scripts: {},
      devDependencies: {},
      engines: {}
    };

    Object.keys(deepPropeties).forEach(category => {
      if (target[category] === undefined) {
        target[category] = {};
      }

      if (template[category] !== undefined) {
        Object.keys(template[category]).forEach(d => {
          if (template[category][d] === '-') {
            if (target[category][d] !== undefined) {
              messages.push(
                `chore(${category}): remove ${d}@${target[category][d]}`
              );
              delete target[category][d];
            }
          } else {
            const tp = context.expand(template[category][d]);

            if (tp !== target[category][d]) {
              messages.push(
                target[category][d] === undefined
                  ? `chore(${category}): add ${d}@${tp} from template`
                  : `chore(${category}): update ${d}@${tp} from template`
              );
              target[category][d] = tp;
            }
          }
        });
      }
    });

    Object.keys(template).forEach(p => {
      if (p !== 'template') {
        if (target[p] === undefined) {
          target[p] = template[p];
        }
      }
    });

    if (target.scripts.prepare) {
      if (buildOutput !== undefined) {
        target.scripts.prepare = target.scripts.prepare.replace(
          /--output=([^\s]+)/,
          `--output=${buildOutput}`
        );
      }
    }

    Object.keys(extraBuilds).forEach(key => {
      target.scripts[key] += ` && ${extraBuilds[key]}`;
    });

    if (target.module === '{{module}}') {
      delete target.module;
    }

    if (
      target.contributors !== undefined &&
      target.author !== undefined &&
      target.author.name !== undefined
    ) {
      const m = target.author.name.match(/(^[^<]+)<([^>]+)>/);
      if (m !== undefined) {
        const name = String(m[1]).replace(/^\s+|\s+$/g, '');
        const email = m[2];

        if (
          target.contributors.find(c => c.name === name && c.email === email)
        ) {
          delete target.author;
        }
      }
    }

    if (
      target.template === undefined ||
      target.template.repository === undefined ||
      target.template.repository.url !==
        `https://github.com/${context.templateRepo.name}.git`
    ) {
      messages.push('chore(package): set template repo');

      target.template = {
        repository: {
          url: `https://github.com/${context.templateRepo.name}.git`
        }
      };
    }

    const toBeDeletedModules = Array.from(
      context.optionalDevModules(new Set(Object.keys(target.devDependencies)))
    ).filter(m => !usedDevModules.has(m));

    /*
    console.log(`modules: ${Object.keys(target.devDependencies)}`);
    console.log(`used modules: ${Array.from(usedDevModules)}`);
    console.log(
      `optional modules: ${Array.from(
        context.optionalDevModules(new Set(Object.keys(target.devDependencies)))
      )}`
    );
    console.log(`toBeDeletedModules: ${Array.from(toBeDeletedModules)}`);
*/

    toBeDeletedModules.forEach(d => {
      messages = messages.filter(
        m => !m.startsWith(`chore(devDependencies): add ${d}@`)
      );
      delete target.devDependencies[d];
    });

    target = deleter(target, template, messages, []);

    if (target.keywords !== undefined) {
      delete target.keywords['npm-package-template'];
    }

    if (
      template.template !== undefined &&
      template.template.keywords !== undefined
    ) {
      Object.keys(template.template.keywords).forEach(r =>
        addKeyword(
          target,
          new RegExp(r),
          template.template.keywords[r],
          messages
        )
      );
    }

    removeKeyword(target, ['null', null, undefined], messages);

    if (messages.length === 0) {
      messages.push('chore: update package.json from template');
    }

    let newContent = JSON.stringify(context.expand(target), undefined, 2);
    const lastChar = newContent[newContent.length - 1];

    // keep trailing newline
    if (originalLastChar === '\n' && lastChar === '}') {
      newContent += '\n';
    }

    return {
      content: newContent,
      messages,
      changed: original !== newContent
    };
  }
}

function deleter(object, reference, messages, path) {
  if (
    typeof object === 'string' ||
    object instanceof String ||
    object === true ||
    object === false ||
    object === undefined ||
    object === null ||
    typeof object === 'number' ||
    object instanceof Number
  ) {
    return object;
  }

  if (Array.isArray(object)) {
    return object.map((e, i) => {
      path.push(i);
      const n = deleter(object[key], reference[key], messages, path);
      path.pop();
      return n;
    });
  }

  Object.keys(reference).forEach(key => {
    path.push(key);

    if (reference[key] === '--delete--' && object[key] !== undefined) {
      if (object[key] !== '--delete--') {
        messages.push(`chore(npm): delete ${path.join('.')}`);
      }
      delete object[key];
    } else {
      object[key] = deleter(object[key], reference[key], messages, path);
    }
    path.pop();
  });

  return object;
}

function removeKeyword(pkg, keywords, messages) {
  if (pkg.keywords !== undefined) {
    keywords.forEach(keyword => {
      if (pkg.keywords.find(k => k === keyword)) {
        messages.push(`docs(package): remove keyword ${keyword}`);
        pkg.keywords = pkg.keywords.filter(k => k !== keyword);
      }
    });

    if (pkg.keywords[0] === null || pkg.keywords[0] === undefined) {
      messages.push(`docs(package): remove keyword null`);
      pkg.keywords = [];
    }
  }
}

function addKeyword(pkg, regex, keyword, messages) {
  if (keyword === undefined || keyword === null || keyword === 'null') {
    return;
  }

  if (pkg.name.match(regex)) {
    if (pkg.keywords === undefined) {
      pkg.keywords = [];
    }
    if (!pkg.keywords.find(k => k === keyword)) {
      messages.push(`docs(package): add keyword ${keyword}`);
      pkg.keywords.push(keyword);
    }
  }
}
<|endoftext|>