<commit_before>import { useEffect, useRef } from 'react'
import Api from '../application/diagram/Api'
import { useActivity } from './activity'

const checkRemoteInterval = 30 * 60 * 1000
const retryFailedRemoteInterval = 5 * 60 * 1000

export const startTime = dateToLocalISO(new Date().toISOString())
export const localSha = process.env.REACT_APP_SHA === '%REACT_APP_SHA%' ? '000000' : process.env.REACT_APP_SHA
export const localShortSha = process.env.REACT_APP_SHA === '%REACT_APP_SHA%' ? '000000' : process.env.REACT_APP_SHA?.substring(0, 6)
export const localBuildTime = process.env.REACT_APP_BUILD_TIME === '%REACT_APP_BUILD_TIME%' ? startTime : process.env.REACT_APP_BUILD_TIME

export const useAppVersionMonitor = () => {
    const [isActive] = useActivity()
    const timerRef = useRef();
    const isRunning = useRef(false)

    useEffect(() => {
        clearTimeout(timerRef.current)
        const getRemoteVersion = async () => {
            if (!isActive || !isRunning.current) {
                isRunning.current = false
                clearTimeout(timerRef.current)
                console.log('Disable remote version check')
                return
            }

            try {
                console.log(`Checking remote, active=${isActive} ...`)
                const api = new Api()
                const manifest = await api.getManifest('/manifest.json')

                const remoteSha = manifest.sha === '%REACT_APP_SHA%' ? '000000' : manifest.sha
                const remoteBuildTime = manifest.buildTime === '%REACT_APP_BUILD_TIME%' ? '' : manifest.buildTime

                console.info(`Local version:  '${localSha.substring(0, 6)}' '${remoteBuildTime}'`)
                console.info(`Remote version: '${remoteSha.substring(0, 6)}' '${remoteBuildTime}'`)

                if (localSha !== remoteSha) {
                    console.info(`Local version: '${localSha.substring(0, 6)}' '${localBuildTime}'`)
                    console.info("Remote version differs, reloading ...")
                    //logger.flush().then(() => window.location.reload(true))
                }
                if (!isRunning.current) {
                    timerRef.current = setTimeout(getRemoteVersion, checkRemoteInterval)
                }

            }
            catch (err) {
                console.error("Failed get remote manifest:", err)
                if (!isRunning.current) {
                    timerRef.current = setTimeout(getRemoteVersion, retryFailedRemoteInterval)
                }
            }
        }
        isRunning.current = true
        getRemoteVersion()

        return () => {
            isRunning.current = false
            clearTimeout(timerRef.current)
        }
    }, [isActive, timerRef, isRunning])
}

function dateToLocalISO(dateText) {
    const date = new Date(dateText)
    const off = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off * 60 * 1000).toISOString().substr(0, 23) +
        (off > 0 ? '-' : '+') +
        (absoff / 60).toFixed(0).padStart(2, '0') + ':' +
        (absoff % 60).toString().padStart(2, '0'))
}

<commit_msg>Adjust<commit_after>import { useEffect, useRef } from 'react'
import Api from '../application/diagram/Api'
import { useActivity } from './activity'

const checkRemoteInterval = 30 * 60 * 1000
const retryFailedRemoteInterval = 5 * 60 * 1000

export const startTime = dateToLocalISO(new Date().toISOString())
export const localSha = process.env.REACT_APP_SHA === '%REACT_APP_SHA%' ? '000000' : process.env.REACT_APP_SHA
export const localShortSha = process.env.REACT_APP_SHA === '%REACT_APP_SHA%' ? '000000' : process.env.REACT_APP_SHA?.substring(0, 6)
export const localBuildTime = process.env.REACT_APP_BUILD_TIME === '%REACT_APP_BUILD_TIME%' ? startTime : process.env.REACT_APP_BUILD_TIME

export const useAppVersionMonitor = () => {
    const [isActive] = useActivity()
    const timerRef = useRef();
    const isRunning = useRef(false)

    useEffect(() => {
        clearTimeout(timerRef.current)
        const getRemoteVersion = async () => {
            if (!isActive || !isRunning.current) {
                isRunning.current = false
                clearTimeout(timerRef.current)
                console.log('Disable remote version check')
                return
            }

            try {
                console.log(`Checking remote, active=${isActive} ...`)
                const api = new Api()
                const manifest = await api.getManifest('/manifest.json')

                const remoteSha = manifest.sha === '%REACT_APP_SHA%' ? localSha : manifest.sha
                const remoteBuildTime = manifest.buildTime === '%REACT_APP_BUILD_TIME%' ? localBuildTime : dateToLocalISO(manifest.buildTime)

                console.info(`Local version:  '${localSha.substring(0, 6)}' '${localBuildTime}'`)
                console.info(`Remote version: '${remoteSha.substring(0, 6)}' '${remoteBuildTime}'`)

                if (localSha !== remoteSha) {
                    console.info(`Local version: '${localSha.substring(0, 6)}' '${localBuildTime}'`)
                    console.info("Remote version differs, reloading ...")
                    //logger.flush().then(() => window.location.reload(true))
                }
                if (!isRunning.current) {
                    timerRef.current = setTimeout(getRemoteVersion, checkRemoteInterval)
                }

            }
            catch (err) {
                console.error("Failed get remote manifest:", err)
                if (!isRunning.current) {
                    timerRef.current = setTimeout(getRemoteVersion, retryFailedRemoteInterval)
                }
            }
        }
        isRunning.current = true
        getRemoteVersion()

        return () => {
            isRunning.current = false
            clearTimeout(timerRef.current)
        }
    }, [isActive, timerRef, isRunning])
}

function dateToLocalISO(dateText) {
    const date = new Date(dateText)
    const off = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off * 60 * 1000).toISOString().substr(0, 23) +
        (off > 0 ? '-' : '+') +
        (absoff / 60).toFixed(0).padStart(2, '0') + ':' +
        (absoff % 60).toString().padStart(2, '0'))
}

<|endoftext|>


<commit_before>'use strict';

var Stream = require('parser').stream;

var programParser = require('./program.js');

window.addEventListener('load', function() {
  document.body.style.margin = '0';

  var ta = document.createElement('textarea');
  ta.style.width = '100vw';
  ta.style.height = '100vh';
  ta.style.padding = '10px';
  ta.style.fontFamily = 'Courier New';
  ta.style.fontSize = '1em';
  ta.style.border = '0';
  ta.style.resize = 'none';
  ta.style.outline = 'none';
  ta.style.boxSizing = 'border-box';

  var button = document.createElement('button');
  var result = document.createElement('div');

  document.body.appendChild(ta);
  ta.focus()

  ta.value = [
    'console = import("console");',
    '',
    'console.log("Hello world!");',
    '',
    'return nil;'
  ].join('\n');

  var check = function() {
    var start = Date.now();
    var stream = new Stream('{' + ta.value + '}');
    var parseResult = programParser(stream);
    var end = Date.now();

    var color = (parseResult.success ? '#dfd' : '#fdd');
    document.body.style.backgroundColor = color;
    ta.style.backgroundColor = color;
    console.log('Parse finished in ' + (end - start) + ' ms');
  };

  ta.addEventListener('input', check);
  check();
});
<commit_msg>Add window.ast to webDemo console<commit_after>'use strict';

var Stream = require('parser').stream;

var programParser = require('./program.js');

window.addEventListener('load', function() {
  document.body.style.margin = '0';

  var ta = document.createElement('textarea');
  ta.style.width = '100vw';
  ta.style.height = '100vh';
  ta.style.padding = '10px';
  ta.style.fontFamily = 'Courier New';
  ta.style.fontSize = '1em';
  ta.style.border = '0';
  ta.style.resize = 'none';
  ta.style.outline = 'none';
  ta.style.boxSizing = 'border-box';

  var button = document.createElement('button');
  var result = document.createElement('div');

  document.body.appendChild(ta);
  ta.focus()

  ta.value = [
    'console = import("console");',
    '',
    'console.log("Hello world!");',
    '',
    'return nil;'
  ].join('\n');

  var check = function() {
    var start = Date.now();
    var stream = new Stream('{' + ta.value + '}');
    var parseResult = programParser(stream);
    var end = Date.now();

    var color = (parseResult.success ? '#dfd' : '#fdd');
    document.body.style.backgroundColor = color;
    ta.style.backgroundColor = color;
    console.log('Parse finished in ' + (end - start) + ' ms');
    window.ast = parseResult.value;
  };

  ta.addEventListener('input', check);
  check();
  console.log('Inspect window.ast to look at the parser output');
});
<|endoftext|>


<commit_before>"use strict";

var ConfigurationData = {
  milestones: {},
  hasTestsuiteFlag: {},
  testsuiteFlagID: -1,

  // useNext represents products where I'm reasonably
  // confident that the correct milestone is --- + 1
  useNext: [
            'Cloud Services',
            'Core',
            'DevTools',
            'Firefox',
            'Firefox Build System',
            'Firefox for Android',
            'GeckoView',
            'MailNews Core',
            'Mozilla Localizations',
            'Other Applications',
            'Remote Protocol',
            'SeaMonkey',
            'Taskcluster',
            'Testing',
            'Thunderbird',
            'Toolkit',
            'WebExtensions'
           ],

  init: function CD_init(loadCallback, errorCallback) {
    var self = this;
    var callback  = function CD_initCallback(errmsg, data) {
      if (errmsg)
        errorCallback(errmsg);
      else
        self.parseData(data, loadCallback);
    };

    var bugzilla = bz.createClient({timeout: 60000});
    bugzilla.getConfiguration(callback);
  },

  parseData: function CD_parseData(data, loadCallback) {
    if (!('product' in data)) {
        loadCallback();
        return;
    }
    // Find the flag number for in-testsuite
    if ('flag_type' in data) {
      for (var flagNumber in data['flag_type']) {
        if (data['flag_type'][flagNumber].name == 'in-testsuite') {
          this.testsuiteFlagID = parseInt(flagNumber);
          break;
        }
      }
    }
    var products = data.product;
    var productMilestones = {}
    for (var product in products) {
      // Parse Milestones
      var active_milestones = products[product].target_milestone_detail.filter(function (milestone) {
        return milestone.is_active;
      }).map(function (milestone) {
        return milestone.name;
      });
      productMilestones[product] = {}
      productMilestones[product].values = active_milestones.map(UI.htmlEncode);
      var dashIndex = active_milestones.indexOf('---');
      if (active_milestones.indexOf('Firefox ' + bugherder.milestone) !== -1) {
        productMilestones[product].defaultIndex = active_milestones.indexOf('Firefox ' + bugherder.milestone);
      } else if (active_milestones.indexOf('mozilla' + bugherder.milestone) !== -1) {
        productMilestones[product].defaultIndex = active_milestones.indexOf('mozilla' + bugherder.milestone);
      } else if (dashIndex != -1) {
        if (dashIndex + 1 < active_milestones.length && this.useNext.indexOf(product) != -1) {
          productMilestones[product].defaultIndex = dashIndex + 1;
        } else {
          productMilestones[product].defaultIndex = dashIndex;
        }
      } else {
        productMilestones[product].defaultIndex = 0;
      }

      // Find which products/components can have in-testsuite set
      if (this.testsuiteFlagID != -1) {
        this.hasTestsuiteFlag[product] = {};
        for (var component in products[product].component) {
          var hasTestsuite = products[product].component[component].flag_type.indexOf(this.testsuiteFlagID) != -1;
          this.hasTestsuiteFlag[product][component] = hasTestsuite;
        }
      }
    }
    this.milestones = productMilestones;
    loadCallback();
  }
};
<commit_msg>Bug 1655711 - Try to detect and set '<number> Branch' milestone<commit_after>"use strict";

var ConfigurationData = {
  milestones: {},
  hasTestsuiteFlag: {},
  testsuiteFlagID: -1,

  // useNext represents products where I'm reasonably
  // confident that the correct milestone is --- + 1
  useNext: [
            'Cloud Services',
            'Core',
            'DevTools',
            'Firefox',
            'Firefox Build System',
            'Firefox for Android',
            'GeckoView',
            'MailNews Core',
            'Mozilla Localizations',
            'Other Applications',
            'Remote Protocol',
            'SeaMonkey',
            'Taskcluster',
            'Testing',
            'Thunderbird',
            'Toolkit',
            'WebExtensions'
           ],

  init: function CD_init(loadCallback, errorCallback) {
    var self = this;
    var callback  = function CD_initCallback(errmsg, data) {
      if (errmsg)
        errorCallback(errmsg);
      else
        self.parseData(data, loadCallback);
    };

    var bugzilla = bz.createClient({timeout: 60000});
    bugzilla.getConfiguration(callback);
  },

  parseData: function CD_parseData(data, loadCallback) {
    if (!('product' in data)) {
        loadCallback();
        return;
    }
    // Find the flag number for in-testsuite
    if ('flag_type' in data) {
      for (var flagNumber in data['flag_type']) {
        if (data['flag_type'][flagNumber].name == 'in-testsuite') {
          this.testsuiteFlagID = parseInt(flagNumber);
          break;
        }
      }
    }
    var products = data.product;
    var productMilestones = {}
    for (var product in products) {
      // Parse Milestones
      var active_milestones = products[product].target_milestone_detail.filter(function (milestone) {
        return milestone.is_active;
      }).map(function (milestone) {
        return milestone.name;
      });
      productMilestones[product] = {}
      productMilestones[product].values = active_milestones.map(UI.htmlEncode);
      var dashIndex = active_milestones.indexOf('---');
      if (active_milestones.indexOf('Firefox ' + bugherder.milestone) !== -1) {
        productMilestones[product].defaultIndex = active_milestones.indexOf('Firefox ' + bugherder.milestone);
      } else if (active_milestones.indexOf('mozilla' + bugherder.milestone) !== -1) {
        productMilestones[product].defaultIndex = active_milestones.indexOf('mozilla' + bugherder.milestone);
      } else if (active_milestones.indexOf(bugherder.milestone + ' Branch') !== -1) {
        productMilestones[product].defaultIndex = active_milestones.indexOf(bugherder.milestone + ' Branch');
      } else if (dashIndex != -1) {
        if (dashIndex + 1 < active_milestones.length && this.useNext.indexOf(product) != -1) {
          productMilestones[product].defaultIndex = dashIndex + 1;
        } else {
          productMilestones[product].defaultIndex = dashIndex;
        }
      } else {
        productMilestones[product].defaultIndex = 0;
      }

      // Find which products/components can have in-testsuite set
      if (this.testsuiteFlagID != -1) {
        this.hasTestsuiteFlag[product] = {};
        for (var component in products[product].component) {
          var hasTestsuite = products[product].component[component].flag_type.indexOf(this.testsuiteFlagID) != -1;
          this.hasTestsuiteFlag[product][component] = hasTestsuite;
        }
      }
    }
    this.milestones = productMilestones;
    loadCallback();
  }
};
<|endoftext|>


<commit_before>import assert from "assert";
import ICS from "../../ics-js/ICS";
import { VERSION } from "../../ics-js/properties";
import {
  InvalidComponentError,
  InvalidProvidedComponentError,
  InvalidProvidedPropError,
  ValidationError
} from "../../ics-js/errors";

console.log(ICS)
const component = new ICS.VCALENDAR();
const prop = new VERSION(2);
const component_2 = new ICS.VEVENT();

describe("Component", function() {
  beforeEach(function() {
    component.reset();
  });

  describe("#constructor()", function() {
    it("should create a new instance of Component", function() {
      assert.equal(component instanceof ICS.Component, true);
    });

    it("should have an empty `_props` instance property", function() {
      assert.deepEqual(component._props, []);
    });

    it("should have an empty `_components` instance property", function() {
      assert.deepEqual(component._components, []);
    });
  });

  describe("#props()", function() {
    it("should not be mutable", function() {
      assert.throws(() => component.props().push(prop), TypeError);
    });

    describe("with no props", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.props(), []);
      });
    });

    describe("with some props", function() {
      it("should return an array with added Property objects", function() {
        component.addProp("VERSION", 2);
        assert.deepEqual(component.props(), [prop]);
      });
    });
  });

  describe("#propNames()", function() {
    describe("with no props", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.propNames(), []);
      });
    });

    describe("with some props", function() {
      it("should return an array with added Property objects' names", function() {
        component.addProp("VERSION", 2);
        assert.deepEqual(component.propNames(), [prop.constructor.propName]);
      });
    });
  });

  describe("#addProp()", function() {
    it("should add a Property", function() {
      component.addProp("VERSION", 2)
      assert.deepEqual(component._props, [prop]);
    });

    it("should throw an InvalidProvidedPropError if passed an invalid (for the component) prop", function() {
      assert.throws(() => component.addProp("DTSTART", new Date()), InvalidProvidedPropError);
    });

    it("should throw an Error if passed a prop against its requirement validations", function() {
      component.addProp("VERSION", 2);
      assert.throws(() => component.addProp("VERSION", 2), ValidationError);
    });
  });

  describe("#components()", function() {
    it("should not be mutable", function() {
      assert.throws(() => component.components().push(component_2), TypeError);
    });

    describe("with no components", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.components(), []);
      });
    });

    describe("with some components", function() {
      it("should return an array with added Component objects", function() {
        component.addComponent(component_2);
        assert.deepEqual(component.components(), [component_2]);
      });
    });
  });

  describe("#componentNames()", function() {
    describe("with no components", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.componentNames(), []);
      });
    });

    describe("with some components", function() {
      it("should return an array with added Component objects' names", function() {
        component.addComponent(component_2);
        assert.deepEqual(component.componentNames(), [component_2.constructor.componentName]);
      });
    });
  });

  describe("#addComponent()", function() {
    it("should add a Component", function() {
      component.addComponent(component_2);
      assert.deepEqual(component._components, [component_2]);
    });

    it("should throw a TypeError if not passed an instance of Component", function() {
      assert.throws(() => component.addComponent("component"), TypeError);
    });

    it("should throw an InvalidProvidedComponentError if passed an invalid (for the component) component", function() {
      const invalid_component = new ICS.VCALENDAR();
      assert.throws(() => component.addComponent(invalid_component), InvalidProvidedComponentError);
    });
  });

  describe("#reset()", function() {
    it("should remove all props and components", function() {
      component.addProp("VERSION", 2);
      component.addComponent(component_2);
      component.reset();
      assert.deepEqual(component._props, []);
      assert.deepEqual(component._components, []);
    })
  });

  describe("#validateRequired()", function() {
    it("should throw an InvalidComponentError if missing required props", function() {
      component.addProp("VERSION", 2);
      assert.throws(() => component.validateRequired(), InvalidComponentError);
    });

    it("should return true if all required props are present", function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
      assert.equal(component.validateRequired(), true);
    });
  });

  describe("#toString()", function() {
    beforeEach(function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
    });

    it("should return a string", function() {
      assert.equal(typeof component.toString(), "string");
    });

    it("should begin and end with prefix and suffix", function() {
      const string = component.toString();
      const separator = component.constructor.separator;
      const splitString = string.split(separator);

      assert.equal(string.startsWith("BEGIN:"), true);
      assert.equal(splitString[splitString.length - 1].startsWith("END:"), true);
    });
  });

  // Tests involving Blob skipped since Node/io.js does not support it.

  describe.skip("#toBlob()", function() {
    beforeEach(function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
    });

    it("should return an instance of Blob", function() {
      assert.equal(component.toBlob() instanceof Blob, true);
    });
  });

  describe.skip("toBase64()", function() {
    beforeEach(function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
    });

    it("should return a string starting with 'data:text/calendar,'", function() {
      const base64 = component.toBase64();

      assert.equal(typeof base64, "string");
      assert.equal(base64.startsWith("data:text/calendar,"), true);
    });
  });
});
<commit_msg>[ci skip] Remove debug code<commit_after>import assert from "assert";
import ICS from "../../ics-js/ICS";
import { VERSION } from "../../ics-js/properties";
import {
  InvalidComponentError,
  InvalidProvidedComponentError,
  InvalidProvidedPropError,
  ValidationError
} from "../../ics-js/errors";

const component = new ICS.VCALENDAR();
const prop = new VERSION(2);
const component_2 = new ICS.VEVENT();

describe("Component", function() {
  beforeEach(function() {
    component.reset();
  });

  describe("#constructor()", function() {
    it("should create a new instance of Component", function() {
      assert.equal(component instanceof ICS.Component, true);
    });

    it("should have an empty `_props` instance property", function() {
      assert.deepEqual(component._props, []);
    });

    it("should have an empty `_components` instance property", function() {
      assert.deepEqual(component._components, []);
    });
  });

  describe("#props()", function() {
    it("should not be mutable", function() {
      assert.throws(() => component.props().push(prop), TypeError);
    });

    describe("with no props", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.props(), []);
      });
    });

    describe("with some props", function() {
      it("should return an array with added Property objects", function() {
        component.addProp("VERSION", 2);
        assert.deepEqual(component.props(), [prop]);
      });
    });
  });

  describe("#propNames()", function() {
    describe("with no props", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.propNames(), []);
      });
    });

    describe("with some props", function() {
      it("should return an array with added Property objects' names", function() {
        component.addProp("VERSION", 2);
        assert.deepEqual(component.propNames(), [prop.constructor.propName]);
      });
    });
  });

  describe("#addProp()", function() {
    it("should add a Property", function() {
      component.addProp("VERSION", 2)
      assert.deepEqual(component._props, [prop]);
    });

    it("should throw an InvalidProvidedPropError if passed an invalid (for the component) prop", function() {
      assert.throws(() => component.addProp("DTSTART", new Date()), InvalidProvidedPropError);
    });

    it("should throw an Error if passed a prop against its requirement validations", function() {
      component.addProp("VERSION", 2);
      assert.throws(() => component.addProp("VERSION", 2), ValidationError);
    });
  });

  describe("#components()", function() {
    it("should not be mutable", function() {
      assert.throws(() => component.components().push(component_2), TypeError);
    });

    describe("with no components", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.components(), []);
      });
    });

    describe("with some components", function() {
      it("should return an array with added Component objects", function() {
        component.addComponent(component_2);
        assert.deepEqual(component.components(), [component_2]);
      });
    });
  });

  describe("#componentNames()", function() {
    describe("with no components", function() {
      it("should return an empty array", function() {
        assert.deepEqual(component.componentNames(), []);
      });
    });

    describe("with some components", function() {
      it("should return an array with added Component objects' names", function() {
        component.addComponent(component_2);
        assert.deepEqual(component.componentNames(), [component_2.constructor.componentName]);
      });
    });
  });

  describe("#addComponent()", function() {
    it("should add a Component", function() {
      component.addComponent(component_2);
      assert.deepEqual(component._components, [component_2]);
    });

    it("should throw a TypeError if not passed an instance of Component", function() {
      assert.throws(() => component.addComponent("component"), TypeError);
    });

    it("should throw an InvalidProvidedComponentError if passed an invalid (for the component) component", function() {
      const invalid_component = new ICS.VCALENDAR();
      assert.throws(() => component.addComponent(invalid_component), InvalidProvidedComponentError);
    });
  });

  describe("#reset()", function() {
    it("should remove all props and components", function() {
      component.addProp("VERSION", 2);
      component.addComponent(component_2);
      component.reset();
      assert.deepEqual(component._props, []);
      assert.deepEqual(component._components, []);
    })
  });

  describe("#validateRequired()", function() {
    it("should throw an InvalidComponentError if missing required props", function() {
      component.addProp("VERSION", 2);
      assert.throws(() => component.validateRequired(), InvalidComponentError);
    });

    it("should return true if all required props are present", function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
      assert.equal(component.validateRequired(), true);
    });
  });

  describe("#toString()", function() {
    beforeEach(function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
    });

    it("should return a string", function() {
      assert.equal(typeof component.toString(), "string");
    });

    it("should begin and end with prefix and suffix", function() {
      const string = component.toString();
      const separator = component.constructor.separator;
      const splitString = string.split(separator);

      assert.equal(string.startsWith("BEGIN:"), true);
      assert.equal(splitString[splitString.length - 1].startsWith("END:"), true);
    });
  });

  // Tests involving Blob skipped since Node/io.js does not support it.

  describe.skip("#toBlob()", function() {
    beforeEach(function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
    });

    it("should return an instance of Blob", function() {
      assert.equal(component.toBlob() instanceof Blob, true);
    });
  });

  describe.skip("toBase64()", function() {
    beforeEach(function() {
      component.addProp("VERSION", 2);
      component.addProp("PRODID", "XYZ Corp");
    });

    it("should return a string starting with 'data:text/calendar,'", function() {
      const base64 = component.toBase64();

      assert.equal(typeof base64, "string");
      assert.equal(base64.startsWith("data:text/calendar,"), true);
    });
  });
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
var showdown  = require('showdown'),
    converter = new showdown.Converter();
converter.setFlavor('github');
var jsdom = require("jsdom");
var serializeDocument = require("jsdom").serializeDocument;
var fs = require("fs");
var documentationContent = fs.readFileSync("../docs_src/documentation.md", "utf-8");
var documentationTemplate = fs.readFileSync("../docs_src/documentation.html", "utf-8");
var demoTemplate = fs.readFileSync("../docs_src/demo.html", "utf-8");
var indexContent = fs.readFileSync("../docs_src/index.md", "utf-8");
var indexHeader = fs.readFileSync("../docs_src/index_header.md", "utf-8");
var ReadMeHeader = fs.readFileSync("../docs_src/README_header.md", "utf-8");
var indexTemplate = fs.readFileSync("../docs_src/index.html", "utf-8");
var polyfill = fs.readFileSync("../polyfills.min.js", "utf-8");
var barbiche = fs.readFileSync("../barbiche.min.js", "utf-8");
var examples = require("../docs_src/examples.json");

jsdom.env({
	html: documentationTemplate,
	src: [polyfill, barbiche],
	done: function (err, window) {
		var document = window.document;
		var Barbiche = window.Barbiche;
		var target = document.querySelector('#target');
		target.innerHTML = converter.makeHtml(documentationContent);
		var barbiche = Barbiche();
		Array.prototype.slice.call(target.querySelectorAll('ul, ol')).forEach(function(list) {
			list.classList.add('ui', 'list');
		});
		var obj = {
			h2: []
		};
		var h3;
		Array.prototype.slice.call(target.querySelectorAll('h2[id], h3[id]')).forEach(function(h) {
			if (h.nodeName == 'H2') {
				var header = window.document.createElement('h4');
				header.classList.add('ui', 'horizontal', 'header', 'divider');
				h.before(header);
				h3 = [];
				obj.h2.push({
					id: h.getAttribute('id'),
					text: h.textContent,
					h3: h3
				});
			} else {
				h3.push({
					id: h.getAttribute('id'),
					text: h.textContent
				})
			}
		});
		Array.prototype.slice.call(target.querySelectorAll('pre code')).forEach(function(code) {
			var classes = code.getAttribute('class');
			var div = document.createElement('div');
			div.classList.add('ui', 'code', 'raised', 'segment', 'hide');
			div.innerHTML = '<textarea class="' + classes + '">' +
				code.textContent.replace(/\n$/, "") + '</textarea>';
			code.parentNode.replaceWith(div);
		});
		document.querySelector('#toc-menu').appendChild(barbiche('toc-template').merge(obj));
		fs.writeFileSync("../docs/documentation.html", serializeDocument(window.document));
  }
});
jsdom.env({
	html: indexTemplate,
	src: [polyfill],
	done: function (err, window) {
		var document = window.document;
		var target = document.querySelector('#target');
		target.innerHTML = converter.makeHtml(indexHeader + indexContent);
		Array.prototype.slice.call(target.querySelectorAll('ul, ol')).forEach(function(list) {
			list.classList.add('ui', 'list');
		});

		Array.prototype.slice.call(target.querySelectorAll('h2')).forEach(function(h) {
			var header = document.createElement('h4');
			header.classList.add('ui', 'horizontal', 'header', 'divider');
			h.before(header);
		});

		Array.prototype.slice.call(target.querySelectorAll('pre code')).forEach(function(code) {
			var classes = code.getAttribute('class');
			var div = document.createElement('div');
			div.classList.add('ui', 'code', 'raised', 'segment', 'hide');
			div.innerHTML = '<textarea class="' + classes + '">' +
				code.textContent.replace(/\n$/, "") + '</textarea>';
			code.parentNode.replaceWith(div);
		});
		Array.prototype.slice.call(target.querySelectorAll('table')).forEach(function(table) {
			table.classList.add('ui', 'celled', 'table');
		});
		fs.writeFileSync("../docs/index.html", serializeDocument(window.document));
  }
});

jsdom.env({
	html: demoTemplate,
	done: function (err, window) {
		var document = window.document;
		var obj = {};
		var buttons = document.querySelector('#buttons');
		examples.forEach(function(example) {
			var button = document.createElement('button');
			button.setAttribute("name", example.name);
			button.setAttribute("class", "ui button");
			var text = document.createTextNode(example.name);
			button.appendChild(text);
			buttons.appendChild(button);
			obj[example.name] = {
				template: example.template,
				js: example.js
			};
			document.querySelector('#target').textContent = "var examples = " + JSON.stringify(obj);
		});
		fs.writeFileSync("../docs/demo.html", serializeDocument(window.document));
  }
});

fs.writeFileSync("../README.md", ReadMeHeader + indexContent);
<commit_msg>Remove dom4 dependency<commit_after>#!/usr/bin/env node
var showdown  = require('showdown'),
    converter = new showdown.Converter();
converter.setFlavor('github');
var jsdom = require("jsdom");
var serializeDocument = require("jsdom").serializeDocument;
var fs = require("fs");
var documentationContent = fs.readFileSync("../docs_src/documentation.md", "utf-8");
var documentationTemplate = fs.readFileSync("../docs_src/documentation.html", "utf-8");
var demoTemplate = fs.readFileSync("../docs_src/demo.html", "utf-8");
var indexContent = fs.readFileSync("../docs_src/index.md", "utf-8");
var indexHeader = fs.readFileSync("../docs_src/index_header.md", "utf-8");
var ReadMeHeader = fs.readFileSync("../docs_src/README_header.md", "utf-8");
var indexTemplate = fs.readFileSync("../docs_src/index.html", "utf-8");
var barbiche = fs.readFileSync("../barbiche.min.js", "utf-8");
var examples = require("../docs_src/examples.json");

jsdom.env({
	html: documentationTemplate,
	src: [barbiche],
	done: function (err, window) {
		var document = window.document;
		var Barbiche = window.Barbiche;
		var target = document.querySelector('#target');
		target.innerHTML =	 converter.makeHtml(documentationContent);
		var barbiche = Barbiche();
		Array.prototype.slice.call(target.querySelectorAll('ul, ol')).forEach(function(list) {
			list.classList.add('ui', 'list');
		});
		var obj = {
			h2: []
		};
		var h3;
		Array.prototype.slice.call(target.querySelectorAll('h2[id], h3[id]')).forEach(function(h) {
			if (h.nodeName == 'H2') {
				var header = window.document.createElement('h4');
				header.classList.add('ui', 'horizontal', 'header', 'divider');
				h.parentNode.insertBefore(header, h);
				h3 = [];
				obj.h2.push({
					id: h.getAttribute('id'),
					text: h.textContent,
					h3: h3
				});
			} else {
				h3.push({
					id: h.getAttribute('id'),
					text: h.textContent
				})
			}
		});
		Array.prototype.slice.call(target.querySelectorAll('pre code')).forEach(function(code) {
			var classes = code.getAttribute('class');
			var div = document.createElement('div');
			div.classList.add('ui', 'code', 'raised', 'segment', 'hide');
			div.innerHTML = '<textarea class="' + classes + '">' +
				code.textContent.replace(/\n$/, "") + '</textarea>';
			code.parentNode.parentNode.replaceChild(div, code.parentNode);
		});
		document.querySelector('#toc-menu').appendChild(barbiche('toc-template').merge(obj));
		fs.writeFileSync("../docs/documentation.html", serializeDocument(window.document));
  }
});
jsdom.env({
	html: indexTemplate,
	done: function (err, window) {
		var document = window.document;
		var target = document.querySelector('#target');
		target.innerHTML = converter.makeHtml(indexHeader + indexContent);
		Array.prototype.slice.call(target.querySelectorAll('ul, ol')).forEach(function(list) {
			list.classList.add('ui', 'list');
		});

		Array.prototype.slice.call(target.querySelectorAll('h2')).forEach(function(h) {
			var header = document.createElement('h4');
			header.classList.add('ui', 'horizontal', 'header', 'divider');
			h.parentNode.insertBefore(header, h);
		});

		Array.prototype.slice.call(target.querySelectorAll('pre code')).forEach(function(code) {
			var classes = code.getAttribute('class');
			var div = document.createElement('div');
			div.classList.add('ui', 'code', 'raised', 'segment', 'hide');
			div.innerHTML = '<textarea class="' + classes + '">' +
				code.textContent.replace(/\n$/, "") + '</textarea>';
			code.parentNode.parentNode.replaceChild(div, code.parentNode);
		});
		Array.prototype.slice.call(target.querySelectorAll('table')).forEach(function(table) {
			table.classList.add('ui', 'celled', 'table');
		});
		fs.writeFileSync("../docs/index.html", serializeDocument(window.document));
  }
});

jsdom.env({
	html: demoTemplate,
	done: function (err, window) {
		var document = window.document;
		var obj = {};
		var buttons = document.querySelector('#buttons');
		examples.forEach(function(example) {
			var button = document.createElement('button');
			button.setAttribute("name", example.name);
			button.setAttribute("class", "ui button");
			var text = document.createTextNode(example.name);
			button.appendChild(text);
			buttons.appendChild(button);
			obj[example.name] = {
				template: example.template,
				js: example.js
			};
			document.querySelector('#target').textContent = "var examples = " + JSON.stringify(obj);
		});
		fs.writeFileSync("../docs/demo.html", serializeDocument(window.document));
  }
});

fs.writeFileSync("../README.md", ReadMeHeader + indexContent);
<|endoftext|>


<commit_before>var s = require('./support');
var t = s.t;

describe('Pume', function () {

    var pume;

    beforeEach(function () {
        pume = s.getPume();
    });

    afterEach(function () {
        pume.close();
    });

    it('should initiate pume', function () {
        t.ok(pume);
        t.ok(pume.adapter);
    });

    it('should subscribe', function (done) {
        var data = {boo: 'foo'};
        var channel = pume.subscribe('tom');
        channel.on('data', function (message) {
            t.deepEqual(data, message);
            done();
        });
        pume.on('connected', function () {
            pume.publish('tom', 'data', data);
        });
    });

    it('should not received data when unsubscribe', function (done) {
        var data = {boo: 'foo'};
        var channel = pume.subscribe('tom');
        channel.on('data', function (message) {
            t.deepEqual(data, message);

            channel.unsubscribe(function () {
                pume.publish('tom', 'data', data);
                setTimeout(done, 200);
            });
        });
        pume.on('connected', function () {
            pume.publish('tom', 'data', data);
        });
    });

    it.only('should sub and pub with different pume', function (done) {
        var pume2 = s.getPume();
        var data = {boo: 'foo'};
        var channel = pume.subscribe('tom');
        channel.on('data', function (message) {
            t.deepEqual(data, message);
            done();
        });
        pume2.on('connected', function () {
            pume2.publish('tom', 'data', data);
        });
    });

});<commit_msg>remove test only<commit_after>var s = require('./support');
var t = s.t;

describe('Pume', function () {

    var pume;

    beforeEach(function () {
        pume = s.getPume();
    });

    afterEach(function () {
        pume.close();
    });

    it('should initiate pume', function () {
        t.ok(pume);
        t.ok(pume.adapter);
    });

    it('should subscribe', function (done) {
        var data = {boo: 'foo'};
        var channel = pume.subscribe('tom');
        channel.on('data', function (message) {
            t.deepEqual(data, message);
            done();
        });
        pume.on('connected', function () {
            pume.publish('tom', 'data', data);
        });
    });

    it('should not received data when unsubscribe', function (done) {
        var data = {boo: 'foo'};
        var channel = pume.subscribe('tom');
        channel.on('data', function (message) {
            t.deepEqual(data, message);

            channel.unsubscribe(function () {
                pume.publish('tom', 'data', data);
                setTimeout(done, 200);
            });
        });
        pume.on('connected', function () {
            pume.publish('tom', 'data', data);
        });
    });

    it('should sub and pub with different pume', function (done) {
        var pume2 = s.getPume();
        var data = {boo: 'foo'};
        var channel = pume.subscribe('tom');
        channel.on('data', function (message) {
            t.deepEqual(data, message);
            done();
        });
        pume2.on('connected', function () {
            pume2.publish('tom', 'data', data);
        });
    });

});<|endoftext|>


<commit_before>var config     = require('../config'),
    Promise    = require('promise'),
    debug      = require('debug')('pulldasher:githubHooks'),
    Pull       = require('../models/pull'),
    Status     = require('../models/status'),
    Signature  = require('../models/signature'),
    Issue      = require('../models/issue'),
    Comment    = require('../models/comment'),
    Label      = require('../models/label'),
    refresh    = require('../lib/refresh'),
    dbManager  = require('../lib/db-manager');

var HooksController = {

   main: function(req, res) {
      // Variable for promise that will resolve when the hook is known to have
      // succeeded or failed.
      var dbUpdated;
      var comment;

      var secret = req.param('secret');
      if (secret !== config.github.hook_secret) {
         var m = 'Invalid Hook Secret: ' + secret;
         debug(m);
         console.error(m);
         return res.status(401).send('Invalid POST');
      }

      // Begin the webhook decoding
      var body = JSON.parse(req.body.payload);
      var event = req.get('X-GitHub-Event');
      debug('Received GitHub webhook, Event: %s', event);

      if (event === 'status') {
         dbUpdated = dbManager.updateCommitStatus(new Status(body));
      } else if (event === 'issues') {
         dbUpdated = handleIssueEvent(body);
      } else if (event === 'pull_request') {
         // Promise that resolves when everything that needs to be done before
         // we call `updatePull` has finished.
         var preUpdate = Promise.resolve();

         switch(body.action) {
            case "opened":
            case "reopened":
            case "closed":
            case "edited":
            case "merged":
               break;
            case "labeled":
               preUpdate = dbManager.insertLabel(
                  new Label(
                     body.label,
                     body.number,
                     body.pull_request.head.repo.name,
                     body.sender.login,
                     body.pull_request.updated_at
                  )
               );
               break;
            case "unlabeled":
               preUpdate = dbManager.deleteLabel(
                  new Label(
                     body.label,
                     body.number,
                     body.pull_request.head.repo.name
                  )
               );
               break;
            case "synchronize":
               preUpdate = dbManager.invalidateSignatures(
                  body.pull_request.number,
                  ['QA', 'CR']
               );
         }

         // Update DB with new pull request content.
         dbUpdated = preUpdate.then(function() {
            return dbManager.updatePull(new Pull(body.pull_request));
         });
      } else if (event === 'issue_comment') {
         if (body.action === 'created') {
            var promises = [];

            // Parse any signature(s) out of the comment.
            var sigs = Signature.parseComment(body.comment, body.issue.number);
            promises.push(dbManager.insertSignatures(sigs));

            body.comment.number = body.issue.number;
            body.comment.repo = body.repository.name;
            body.comment.type = 'issue';
            comment = new Comment(body.comment);

            promises.push(dbManager.updateComment(comment));

            dbUpdated = Promise.all(promises);
         } else {
            // If the comment was edited or deleted, the easiest way to deal
            // with the result is to simply refresh all data for the pull (or
            // issue). Otherwise, we'd have to delete or update the comment,
            // delete or update any signatures tied to that comment, then
            // delete all signatures and re-insert in order them so the
            // dev_blocking and such comes out correct.
            refreshPullOrIssue(body);
         }
      } else if (event === 'pull_request_review_comment') {
         if (body.action === 'deleted') {
            dbUpdated = dbManager.deleteReviewComment(body.comment.id);
         } else {
            body.comment.number = body.pull_request.number;
            body.comment.repo =   body.repository.name;
            body.comment.type =   'review';
            comment = new Comment(body.comment);

            dbUpdated = dbManager.updateComment(comment);
         }
      }

      if (dbUpdated) {
         dbUpdated.then(function fulfilled() {
            res.status(200).send('Success!');
         },
         function rejected(err) {
            console.log(err);
            res.status(500).send(err.toString());
         }).done();
      } else {
         res.status(200).send('Success!');
      }
   }
};

function handleIssueEvent(body) {
   debug('Webhook action: %s for issue #%s', body.action, body.issue.number);
   var doneHandling = handleLabelEvents(body);

   switch(body.action) {
      case "opened":
         // Always do this for opened issues because a full refresh
         // is the easiest way to get *who* assigned the initial labels.
         return refresh.issue(body.issue.number);

      case "reopened":
      case "closed":
      case "edited":
      case "assigned":
      case "unassigned":
        // Default case is update the issue
   }

   return doneHandling.then(function() {
      return Issue.getFromGH(body.issue);
   })
   .then(dbManager.updateIssue)
   .then(function() {
      return reprocessLabels(body.issue.number, body.repository.name);
   });
}

/**
 * Handles the response body if it represents a labeled / unlabled issue
 * (or pull) event and returns a promise that is fulfilled when the DB change
 * is committed.
 *
 * Note: will return a fulfilled promise if this is not a label event.
 */
function handleLabelEvents(body) {
   switch(body.action) {
      case "labeled":
         debug('Added label: %s', body.label.name);
         return dbManager.insertLabel(new Label(
            body.label,
            body.issue.number,
            body.repository.name,
            body.sender.login,
            body.issue.updated_at
         ));

      case "unlabeled":
         debug('Removed label: %s', body.label.name);
         return dbManager.deleteLabel(new Label(
            body.label,
            body.issue.number,
            body.repository.name
         ));
   }
   return Promise.resolve();
}

/**
 * After a label has been added or removed we have to re-process all the labels
 * in case one of them matches one of our configured label updaters.
 */
function reprocessLabels(issueNumber, repo) {
   if (!config.labels || !config.labels.length) {
      return;
   }
   debug("Reprocessing labels for Issue #%s", issueNumber);
   return dbManager.getIssue(issueNumber, repo)
   .then(dbManager.updateIssue);
}

function refreshPullOrIssue(responseBody) {
   // The Docs: https://developer.github.com/v3/issues/#list-issues say you can
   // tell the difference like this:
   if (responseBody.issue.pull_request) {
      refresh.pull(responseBody.issue.number);
   } else {
      refresh.issue(responseBody.issue.number);
   }
}

module.exports = HooksController;
<commit_msg>Hooks: simmplify pull label event handling<commit_after>var config     = require('../config'),
    Promise    = require('promise'),
    debug      = require('debug')('pulldasher:githubHooks'),
    Pull       = require('../models/pull'),
    Status     = require('../models/status'),
    Signature  = require('../models/signature'),
    Issue      = require('../models/issue'),
    Comment    = require('../models/comment'),
    Label      = require('../models/label'),
    refresh    = require('../lib/refresh'),
    dbManager  = require('../lib/db-manager');

var HooksController = {

   main: function(req, res) {
      // Variable for promise that will resolve when the hook is known to have
      // succeeded or failed.
      var dbUpdated;
      var comment;

      var secret = req.param('secret');
      if (secret !== config.github.hook_secret) {
         var m = 'Invalid Hook Secret: ' + secret;
         debug(m);
         console.error(m);
         return res.status(401).send('Invalid POST');
      }

      // Begin the webhook decoding
      var body = JSON.parse(req.body.payload);
      var event = req.get('X-GitHub-Event');
      debug('Received GitHub webhook, Event: %s', event);

      if (event === 'status') {
         dbUpdated = dbManager.updateCommitStatus(new Status(body));
      } else if (event === 'issues') {
         dbUpdated = handleIssueEvent(body);
      } else if (event === 'pull_request') {
         // Promise that resolves when everything that needs to be done before
         // we call `updatePull` has finished.
         var preUpdate = Promise.resolve();

         switch(body.action) {
            case "opened":
            case "reopened":
            case "closed":
            case "edited":
            case "merged":
               break;
            case "labeled":
               preUpdate = dbManager.insertLabel(
                  new Label(
                     body.label,
                     body.pull_request.number,
                     body.repository.name,
                     body.sender.login,
                     body.pull_request.updated_at
                  )
               );
               break;
            case "unlabeled":
               preUpdate = dbManager.deleteLabel(
                  new Label(
                     body.label,
                     body.pull_request.number,
                     body.repository.name
                  )
               );
               break;
            case "synchronize":
               preUpdate = dbManager.invalidateSignatures(
                  body.pull_request.number,
                  ['QA', 'CR']
               );
         }

         // Update DB with new pull request content.
         dbUpdated = preUpdate.then(function() {
            return dbManager.updatePull(new Pull(body.pull_request));
         });
      } else if (event === 'issue_comment') {
         if (body.action === 'created') {
            var promises = [];

            // Parse any signature(s) out of the comment.
            var sigs = Signature.parseComment(body.comment, body.issue.number);
            promises.push(dbManager.insertSignatures(sigs));

            body.comment.number = body.issue.number;
            body.comment.repo = body.repository.name;
            body.comment.type = 'issue';
            comment = new Comment(body.comment);

            promises.push(dbManager.updateComment(comment));

            dbUpdated = Promise.all(promises);
         } else {
            // If the comment was edited or deleted, the easiest way to deal
            // with the result is to simply refresh all data for the pull (or
            // issue). Otherwise, we'd have to delete or update the comment,
            // delete or update any signatures tied to that comment, then
            // delete all signatures and re-insert in order them so the
            // dev_blocking and such comes out correct.
            refreshPullOrIssue(body);
         }
      } else if (event === 'pull_request_review_comment') {
         if (body.action === 'deleted') {
            dbUpdated = dbManager.deleteReviewComment(body.comment.id);
         } else {
            body.comment.number = body.pull_request.number;
            body.comment.repo =   body.repository.name;
            body.comment.type =   'review';
            comment = new Comment(body.comment);

            dbUpdated = dbManager.updateComment(comment);
         }
      }

      if (dbUpdated) {
         dbUpdated.then(function fulfilled() {
            res.status(200).send('Success!');
         },
         function rejected(err) {
            console.log(err);
            res.status(500).send(err.toString());
         }).done();
      } else {
         res.status(200).send('Success!');
      }
   }
};

function handleIssueEvent(body) {
   debug('Webhook action: %s for issue #%s', body.action, body.issue.number);
   var doneHandling = handleLabelEvents(body);

   switch(body.action) {
      case "opened":
         // Always do this for opened issues because a full refresh
         // is the easiest way to get *who* assigned the initial labels.
         return refresh.issue(body.issue.number);

      case "reopened":
      case "closed":
      case "edited":
      case "assigned":
      case "unassigned":
        // Default case is update the issue
   }

   return doneHandling.then(function() {
      return Issue.getFromGH(body.issue);
   })
   .then(dbManager.updateIssue)
   .then(function() {
      return reprocessLabels(body.issue.number, body.repository.name);
   });
}

/**
 * Handles the response body if it represents a labeled / unlabled issue
 * (or pull) event and returns a promise that is fulfilled when the DB change
 * is committed.
 *
 * Note: will return a fulfilled promise if this is not a label event.
 */
function handleLabelEvents(body) {
   switch(body.action) {
      case "labeled":
         debug('Added label: %s', body.label.name);
         return dbManager.insertLabel(new Label(
            body.label,
            body.issue.number,
            body.repository.name,
            body.sender.login,
            body.issue.updated_at
         ));

      case "unlabeled":
         debug('Removed label: %s', body.label.name);
         return dbManager.deleteLabel(new Label(
            body.label,
            body.issue.number,
            body.repository.name
         ));
   }
   return Promise.resolve();
}

/**
 * After a label has been added or removed we have to re-process all the labels
 * in case one of them matches one of our configured label updaters.
 */
function reprocessLabels(issueNumber, repo) {
   if (!config.labels || !config.labels.length) {
      return;
   }
   debug("Reprocessing labels for Issue #%s", issueNumber);
   return dbManager.getIssue(issueNumber, repo)
   .then(dbManager.updateIssue);
}

function refreshPullOrIssue(responseBody) {
   // The Docs: https://developer.github.com/v3/issues/#list-issues say you can
   // tell the difference like this:
   if (responseBody.issue.pull_request) {
      refresh.pull(responseBody.issue.number);
   } else {
      refresh.issue(responseBody.issue.number);
   }
}

module.exports = HooksController;
<|endoftext|>


<commit_before>// StashBoard :{
stashboard = {};

stashboard.start = function(){
  var previous = document.getElementById("stashboardJavascript");
  if (previous){
    previous.parentNode.removeChild(previous);
  }

  var jsonp = document.createElement('script');
  jsonp.setAttribute("id", "stashboardJavascript");
  jsonp.setAttribute("src","http://ismywebservicedown.appspot.com/api/v1/services?callback=stashboard.callback&random=" + Math.random());
  jsonp.setAttribute("type", "text/javascript");
  document.body.appendChild(jsonp);
};

stashboard.callback = function(data){
  var services = data.services || [];
  var severity = 0;
  var summary = "green";
  var escalate = null;
  var serv = null;

  var levels = {
    NORMAL: [0, "green"],
    WARNING: [10, "yellow"],
    ERROR: [20, "red"],
    CRITICAL: [30, "red"]
  };

  for (var i=0; i < services.length; i++) {
    var service = services[i];
    var evt = service["current-event"];
    var level = null;

    if (evt) {
      level = evt.status.level;
    }

    if (level && levels[level][0] > severity) {
      escalate = evt;
      summary = levels[level][1];
      severity = levels[level][0];
      serv = service;
    }

  }

  var div = document.createElement('div');
  var style = "width: 65px; height: 70px; position: absolute; top: 0px; right: 45px;background:#ccc;-moz-border-radius-bottomleft: 15px; -webkit-border-bottom-left-radius: 15px;-moz-border-radius-bottomright: 15px; -webkit-border-bottom-right-radius: 15px;border-bottom-right-radius: 15px; border-bottom-left-radius: 15px;border-bottom: 1px solid #999; border-left: 1px solid #999; border-right: 1px solid #999;-moz-box-shadow: 0px 0px 10px #ccc; -webkit-box-shadow: 0px 0px 10px #ccc; z-index: 9999";
  div.setAttribute("style", style);

  var img = document.createElement('img');
  img.setAttribute("style", "width: 64px; border: 0");
  img.setAttribute("src", "http://ismywebservicedown.appspot.com/images/widget/" + summary + ".png");

  var a = document.createElement('a');
  a.setAttribute("style", "text-decoration: none; border: 0;");
  a.setAttribute("href", "http://ismywebservicedown.appspot.com/");
  a.appendChild(img);
  div.appendChild(a);
  var previous = document.getElementById("stashboardStatus");
  if (previous){
    previous.parentNode.removeChild(previous);
  }
  div.setAttribute("id", "stashboardStatus");
  document.body.appendChild(div);

  var message = null;
  if (escalate) {
    message = document.createElement('div');
    message.setAttribute("style", "-webkit-border-bottom-left-radius: 15px; -webkit-border-bottom-right-radius: 15px; border-bottom-right-radius: 15px; border-bottom-left-radius: 15px; position: absolute;top: 0px;height: 45px;right: 20px;padding: 0px 105px 0 15px;line-height: 45px;-moz-box-shadow: 0px 0px 8px rgb(204, 204, 204);-moz-border-radius-bottomleft: 15px;-moz-border-radius-bottomright: 15px;border-bottom: 1px solid #ccc;border-left: 1px solid #ccc;border-right: 1px solid #ccc; background: #eee;z-index: 99;");

    img = document.createElement('img');
    img.setAttribute("style", "float: left; margin: 14px 10px 0 0;");
    img.setAttribute("src", escalate.status.image);

    var strong = document.createElement('strong');
    strong.innerHTML = serv.name + ":  ";

    var p = document.createElement('span');
    p.innerHTML = escalate.message;

    message.appendChild(img);
    message.appendChild(strong);
    message.appendChild(p);
  }

  previous = document.getElementById("stashboardMessage");
  if (previous){
    previous.parentNode.removeChild(previous);
  }
  if (message){
    message.setAttribute("id", "stashboardMessage");
    document.body.appendChild(message);
  }

  setTimeout(stashboard.start, 2000);

};

window.onload = stashboard.start;

  <commit_msg>Changed the update check to 4 secs<commit_after>// StashBoard :{
stashboard = {};

stashboard.start = function(){
  var previous = document.getElementById("stashboardJavascript");
  if (previous){
    previous.parentNode.removeChild(previous);
  }

  var jsonp = document.createElement('script');
  jsonp.setAttribute("id", "stashboardJavascript");
  jsonp.setAttribute("src","http://ismywebservicedown.appspot.com/api/v1/services?callback=stashboard.callback&random=" + Math.random());
  jsonp.setAttribute("type", "text/javascript");
  document.body.appendChild(jsonp);
};

stashboard.callback = function(data){
  var services = data.services || [];
  var severity = 0;
  var summary = "green";
  var escalate = null;
  var serv = null;

  var levels = {
    NORMAL: [0, "green"],
    WARNING: [10, "yellow"],
    ERROR: [20, "red"],
    CRITICAL: [30, "red"]
  };

  for (var i=0; i < services.length; i++) {
    var service = services[i];
    var evt = service["current-event"];
    var level = null;

    if (evt) {
      level = evt.status.level;
    }

    if (level && levels[level][0] > severity) {
      escalate = evt;
      summary = levels[level][1];
      severity = levels[level][0];
      serv = service;
    }

  }

  var div = document.createElement('div');
  var style = "width: 65px; height: 70px; position: absolute; top: 0px; right: 45px;background:#ccc;-moz-border-radius-bottomleft: 15px; -webkit-border-bottom-left-radius: 15px;-moz-border-radius-bottomright: 15px; -webkit-border-bottom-right-radius: 15px;border-bottom-right-radius: 15px; border-bottom-left-radius: 15px;border-bottom: 1px solid #999; border-left: 1px solid #999; border-right: 1px solid #999;-moz-box-shadow: 0px 0px 10px #ccc; -webkit-box-shadow: 0px 0px 10px #ccc; z-index: 9999";
  div.setAttribute("style", style);

  var img = document.createElement('img');
  img.setAttribute("style", "width: 64px; border: 0");
  img.setAttribute("src", "http://ismywebservicedown.appspot.com/images/widget/" + summary + ".png");

  var a = document.createElement('a');
  a.setAttribute("style", "text-decoration: none; border: 0;");
  a.setAttribute("href", "http://ismywebservicedown.appspot.com/");
  a.appendChild(img);
  div.appendChild(a);
  var previous = document.getElementById("stashboardStatus");
  if (previous){
    previous.parentNode.removeChild(previous);
  }
  div.setAttribute("id", "stashboardStatus");
  document.body.appendChild(div);

  var message = null;
  if (escalate) {
    message = document.createElement('div');
    message.setAttribute("style", "-webkit-border-bottom-left-radius: 15px; -webkit-border-bottom-right-radius: 15px; border-bottom-right-radius: 15px; border-bottom-left-radius: 15px; position: absolute;top: 0px;height: 45px;right: 20px;padding: 0px 105px 0 15px;line-height: 45px;-moz-box-shadow: 0px 0px 8px rgb(204, 204, 204);-moz-border-radius-bottomleft: 15px;-moz-border-radius-bottomright: 15px;border-bottom: 1px solid #ccc;border-left: 1px solid #ccc;border-right: 1px solid #ccc; background: #eee;z-index: 99;");

    img = document.createElement('img');
    img.setAttribute("style", "float: left; margin: 14px 10px 0 0;");
    img.setAttribute("src", escalate.status.image);

    var strong = document.createElement('strong');
    strong.innerHTML = serv.name + ":  ";

    var p = document.createElement('span');
    p.innerHTML = escalate.message;

    message.appendChild(img);
    message.appendChild(strong);
    message.appendChild(p);
  }

  previous = document.getElementById("stashboardMessage");
  if (previous){
    previous.parentNode.removeChild(previous);
  }
  if (message){
    message.setAttribute("id", "stashboardMessage");
    document.body.appendChild(message);
  }

  setTimeout(stashboard.start, 4000);

};

window.onload = stashboard.start;

  <|endoftext|>


<commit_before>/*!
 * chai
 * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

module.exports = function (chai) {
  var Assertion = chai.Assertion;

  chai.should = function () {
    // modify Object.prototype to have `should`
    Object.defineProperty(Object.prototype, 'should', {
      set: function(){},
      get: function(){
        if (this instanceof String || this instanceof Number) {
          return new Assertion(this.constructor(this));
        } else if (this instanceof Boolean) {
          return new Assertion(this == true);
        }
        return new Assertion(this);
      },
      configurable: true
    });

    var should = {};

    should.equal = function (val1, val2) {
      new Assertion(val1).to.equal(val2);
    };

    should.throw = function (fn, err) {
      new Assertion(fn).to.throw(err);
    };

    should.exist = function (val) {
      new Assertion(val).to.exist;
    }

    // negation
    should.not = {}

    should.not.equal = function (val1, val2) {
      new Assertion(val1).to.not.equal(val2);
    };

    should.not.throw = function (fn, err) {
      new Assertion(fn).to.not.throw(err);
    };

    should.not.exist = function (val) {
      new Assertion(val).to.not.exist;
    }

    return should;
  };
};
<commit_msg>Should interface supports multiple throw parameters<commit_after>/*!
 * chai
 * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

module.exports = function (chai) {
  var Assertion = chai.Assertion;

  chai.should = function () {
    // modify Object.prototype to have `should`
    Object.defineProperty(Object.prototype, 'should', {
      set: function(){},
      get: function(){
        if (this instanceof String || this instanceof Number) {
          return new Assertion(this.constructor(this));
        } else if (this instanceof Boolean) {
          return new Assertion(this == true);
        }
        return new Assertion(this);
      },
      configurable: true
    });

    var should = {};

    should.equal = function (val1, val2) {
      new Assertion(val1).to.equal(val2);
    };

    should.throw = function (fn, errt, errs) {
      new Assertion(fn).to.throw(errt, errs);
    };

    should.exist = function (val) {
      new Assertion(val).to.exist;
    }

    // negation
    should.not = {}

    should.not.equal = function (val1, val2) {
      new Assertion(val1).to.not.equal(val2);
    };

    should.not.throw = function (fn, errt, errs) {
      new Assertion(fn).to.not.throw(errt, errs);
    };

    should.not.exist = function (val) {
      new Assertion(val).to.not.exist;
    }

    return should;
  };
};
<|endoftext|>


<commit_before>/*jslint node:true indent:2 nomen:true */
/*globals jasmine, expect, describe, it, beforeEach, spyOn */
'use strict';

var jSend = require('../'),
  httpMocks = require('node-mocks-http'),
  assert = require('assert'),
  functionCalled,
  req,
  res,
  next;

function getResponseData() {
  return JSON.parse(res._getData());
}

beforeEach(function () {
  functionCalled = false;
  req = httpMocks.createRequest();
  res = httpMocks.createResponse();
  next = function () { return; };
  spyOn(res, 'json').and.callThrough();
});

describe('jSend', function () {
  it('should exist', function () {
    assert(jSend);
  });
  it('should be a function', function () {
    assert(typeof jSend === 'function');
  });
  it('should call third parameter "next" function as callback', function () {
    next = jasmine.createSpy('spy');
    jSend(req, res, next);
    expect(next).toHaveBeenCalled();
  });
  it('should add jSend to res object', function () {
    jSend(req, res, next);
    assert(res.jSend);
  });
  describe('res.jSend', function () {
    beforeEach(function () {
      jSend(req, res, next);
    });
    it('should be a function', function () {
      assert(typeof res.jSend === 'function');
    });
    it('should call res.json when invoked', function () {
      res.jSend();
      expect(res.json).toHaveBeenCalled();
    });
    it('should send object to res.json when invoked', function () {
      res.jSend();
      expect(res.json).toHaveBeenCalledWith(jasmine.any(Object));
    });
    it('should send response with status set to "success"', function () {
      res.jSend();
      expect(getResponseData().status).toBe('success');
    });
    it('should send response with data set to null', function () {
      res.jSend();
      assert(getResponseData().data === null);
    });
    it('should send response with data set to res.jSend parameter', function () {
      var data = [ 'this', 'is', 'a', 'test' ];
      res.jSend(data);
      assert.deepEqual(getResponseData().data, data);
    });
    it('should send response code of 200', function () {
      res.jSend();
      assert.equal(res.statusCode, 200);
    });
    it('should send response code of 201 if request was a POST', function () {
      req.method = 'POST';
      res.jSend();
      expect(res.statusCode).toBe(201);
    });
    it('should send data of null if request was a DELETE', function () {
      req.method = 'DELETE';
      res.jSend([ 'this', 'should', 'not', 'be', 'sent', 'as', 'data']);
      assert(getResponseData().data === null);
    });

    describe('res.jSend.error', function () {
      it('should be function', function () {
        expect(res.jSend.error).toEqual(jasmine.any(Function));
      });
      it('should throw correct error if invoked without an argument', function () {
        expect(res.jSend.error).toThrowError('res.jSend.error invoked without argument');
      });
      it('should throw correct error if status not defined', function () {
        expect(function () {
          res.jSend.error({message: 'foo'});
        }).toThrowError('res.jSend.error options validation: expected property status to be of type number (was undefined)');
      });
      it('should throw correct error if message not defined', function () {
        expect(function () {
          res.jSend.error({status: 500});
        }).toThrowError('res.jSend.error options validation: expected property message to be of type string (was undefined)');
      });
      it('should set res status code to specified status', function () {
        res.jSend.error({status: 501, message: 'Not Implemented'});
        assert.equal(res.statusCode, 501);
      });
      //it('should set res data status to error', function () {
    });
  });
});
<commit_msg>Red: Add test res.jSend.error sets status to error<commit_after>/*jslint node:true indent:2 nomen:true */
/*globals jasmine, expect, describe, it, beforeEach, spyOn */
'use strict';

var jSend = require('../'),
  httpMocks = require('node-mocks-http'),
  assert = require('assert'),
  functionCalled,
  req,
  res,
  next;

function getResponseData() {
  return JSON.parse(res._getData());
}

beforeEach(function () {
  functionCalled = false;
  req = httpMocks.createRequest();
  res = httpMocks.createResponse();
  next = function () { return; };
  spyOn(res, 'json').and.callThrough();
});

describe('jSend', function () {
  it('should exist', function () {
    assert(jSend);
  });
  it('should be a function', function () {
    assert(typeof jSend === 'function');
  });
  it('should call third parameter "next" function as callback', function () {
    next = jasmine.createSpy('spy');
    jSend(req, res, next);
    expect(next).toHaveBeenCalled();
  });
  it('should add jSend to res object', function () {
    jSend(req, res, next);
    assert(res.jSend);
  });
  describe('res.jSend', function () {
    beforeEach(function () {
      jSend(req, res, next);
    });
    it('should be a function', function () {
      assert(typeof res.jSend === 'function');
    });
    it('should call res.json when invoked', function () {
      res.jSend();
      expect(res.json).toHaveBeenCalled();
    });
    it('should send object to res.json when invoked', function () {
      res.jSend();
      expect(res.json).toHaveBeenCalledWith(jasmine.any(Object));
    });
    it('should send response with status set to "success"', function () {
      res.jSend();
      expect(getResponseData().status).toBe('success');
    });
    it('should send response with data set to null', function () {
      res.jSend();
      assert(getResponseData().data === null);
    });
    it('should send response with data set to res.jSend parameter', function () {
      var data = [ 'this', 'is', 'a', 'test' ];
      res.jSend(data);
      assert.deepEqual(getResponseData().data, data);
    });
    it('should send response code of 200', function () {
      res.jSend();
      assert.equal(res.statusCode, 200);
    });
    it('should send response code of 201 if request was a POST', function () {
      req.method = 'POST';
      res.jSend();
      expect(res.statusCode).toBe(201);
    });
    it('should send data of null if request was a DELETE', function () {
      req.method = 'DELETE';
      res.jSend([ 'this', 'should', 'not', 'be', 'sent', 'as', 'data']);
      assert(getResponseData().data === null);
    });

    describe('res.jSend.error', function () {
      it('should be function', function () {
        expect(res.jSend.error).toEqual(jasmine.any(Function));
      });
      it('should throw correct error if invoked without an argument', function () {
        expect(res.jSend.error).toThrowError('res.jSend.error invoked without argument');
      });
      it('should throw correct error if status not defined', function () {
        expect(function () {
          res.jSend.error({message: 'foo'});
        }).toThrowError('res.jSend.error options validation: expected property status to be of type number (was undefined)');
      });
      it('should throw correct error if message not defined', function () {
        expect(function () {
          res.jSend.error({status: 500});
        }).toThrowError('res.jSend.error options validation: expected property message to be of type string (was undefined)');
      });
      it('should set res status code to specified status', function () {
        res.jSend.error({status: 501, message: 'Not Implemented'});
        expect(res.statusCode).toEqual(501);
      });
      it('should set res data status to error', function () {
        res.jSend.error({status: 500, message: 'Internal Server Error'});
        expect(getResponseData().status).toEqual('error');
      });
    });
  });
});
<|endoftext|>


<commit_before>'use babel'

import Path from 'path'
import {exec, execNode} from '../'
import {it} from './helpers'

const PATH_NODE = Path.join(__dirname, 'fixtures', 'node.js')
const PATH_WAIT = Path.join(__dirname, 'fixtures', 'wait.js')
const PATH_ENV = Path.join(__dirname, 'fixtures', 'env.js')

describe('exec', function() {
  it('works with stdout', async function() {
    const result = await exec(process.execPath, [PATH_NODE])
    expect(result).toBe('STDOUT')
  })

  it('throws if we are expecting on stderr and get on stdout', async function() {
    try {
      const result = await exec(process.execPath, [PATH_NODE, 'error'])
      expect(false).toBe(true)
    } catch (_) {
      expect(_.message).toBe('STDERR')
    }
  })

  it('doesnt mind when we are expecting on stderr though', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'error'], {stream: 'stderr'})
    expect(result).toBe('STDERR')
  })

  it('also supports giving out both streams at once', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'error'], {stream: 'both'})
    expect(result.stderr).toBe('STDERR')
    expect(result.stdout).toBe('STDOUT')
  })

  it('passes on stdin properly', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'input'], {stdin: 'hello dolly'})
    expect(result).toBe('STDOUThello dolly')
  })

  it('ignores stderr if throwOnStdErr is specified', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'error'], {throwOnStdErr: false})
    expect(result).toBe('STDOUT')
  })

  it('acts like a good buy if script terminates before timeout', async function() {
    const result = await exec(process.execPath, [PATH_WAIT, '1000'], {timeout: 1500})
    expect(result).toBe('PASSED')
  })

  it('termintes the script and errors if the process times out', async function() {
    try {
      await exec(process.execPath, [PATH_WAIT, '2000'], {timeout: 1000})
      expect(false).toBe(true)
    } catch (_) {
      expect(_.message).toContain('timed out')
    }
  })

  it('ignores timeouts completely if no timeout is specified', async function() {
    const result = await exec(process.execPath, [PATH_WAIT, '7000'])
    expect(result).toBe('PASSED')
  })

  it('passes env properly', async function() {
    const result = await exec(process.execPath, [PATH_ENV], {env: {
      SOMETHING: 'Hello',
      SOMETHING_ELSE: 'Dolly'
    }})
    expect(result).toBe('Hello\nDolly')
  })

  it('works well with stdio: inherit', async function() {
    const result = await exec(process.execPath, [PATH_ENV], {env: {
      SOMETHING: 'Hello',
      SOMETHING_ELSE: 'Dolly'
    }, stdio: 'inherit'})
    expect(result).toBe('Hello\nDolly')
  })
})
<commit_msg>:bug: Fix a spec<commit_after>'use babel'

import Path from 'path'
import {exec, execNode} from '../'
import {it} from './helpers'

const PATH_NODE = Path.join(__dirname, 'fixtures', 'node.js')
const PATH_WAIT = Path.join(__dirname, 'fixtures', 'wait.js')
const PATH_ENV = Path.join(__dirname, 'fixtures', 'env.js')

describe('exec', function() {
  it('works with stdout', async function() {
    const result = await exec(process.execPath, [PATH_NODE])
    expect(result).toBe('STDOUT')
  })

  it('throws if we are expecting on stderr and get on stdout', async function() {
    try {
      const result = await exec(process.execPath, [PATH_NODE, 'error'])
      expect(false).toBe(true)
    } catch (_) {
      expect(_.message).toBe('STDERR')
    }
  })

  it('doesnt mind when we are expecting on stderr though', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'error'], {stream: 'stderr'})
    expect(result).toBe('STDERR')
  })

  it('also supports giving out both streams at once', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'error'], {stream: 'both'})
    expect(result.stderr).toBe('STDERR')
    expect(result.stdout).toBe('STDOUT')
  })

  it('passes on stdin properly', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'input'], {stdin: 'hello dolly'})
    expect(result).toBe('STDOUThello dolly')
  })

  it('ignores stderr if throwOnStdErr is specified', async function() {
    const result = await exec(process.execPath, [PATH_NODE, 'error'], {throwOnStdErr: false})
    expect(result).toBe('STDOUT')
  })

  it('acts like a good buy if script terminates before timeout', async function() {
    const result = await exec(process.execPath, [PATH_WAIT, '1000'], {timeout: 1500})
    expect(result).toBe('PASSED')
  })

  it('termintes the script and errors if the process times out', async function() {
    try {
      await exec(process.execPath, [PATH_WAIT, '2000'], {timeout: 1000})
      expect(false).toBe(true)
    } catch (_) {
      expect(_.message).toContain('timed out')
    }
  })

  it('ignores timeouts completely if no timeout is specified', async function() {
    const result = await exec(process.execPath, [PATH_WAIT, '7000'])
    expect(result).toBe('PASSED')
  })

  it('passes env properly', async function() {
    const result = await exec(process.execPath, [PATH_ENV], {env: {
      SOMETHING: 'Hello',
      SOMETHING_ELSE: 'Dolly'
    }})
    expect(result).toBe('Hello\nDolly')
  })

  it('works well with stdio: inherit', async function() {
    const result = await exec(process.execPath, [PATH_ENV], {env: {
      SOMETHING: 'Hello',
      SOMETHING_ELSE: 'Dolly'
    }, stdio: 'inherit'})
    expect(result).toBe('')
  })
})
<|endoftext|>


<commit_before>// ==UserScript==
// @name              Pixiv自動ブックマークタグ付け
// @description       Pixivのブックマークタグ付けを半自動化してくれる
// @include           http://www.pixiv.net/bookmark_add.php?type=illust&illust_id=*
// @include           http://www.pixiv.net/member_illust.php?mode=medium&illust_id=*
// @run-at            document-end
// @version           0.2.1
// ==/UserScript==

// デフォルトルール
var defaultRuleStr = 'private R-18';

// 設定テキストを解析し、連想配列で返す
var parseRules = function(ruleStr) {
	var patternRule    = [];
	var patternAllRule = [];
	var privateRule    = [];
	var errors         = [];

	// 正規表現を表す文字列のリストから、正規表現のリストを作成
	var createRegExpFromStrAry = function(regexpStrAry, lineNumber) {
		var regexps = [];
		regexpStrAry.forEach(function(regexpStr) {
			try { regexps.push(new RegExp(regexpStr)); }
			catch (e) { errors.push({ lineNumber: lineNumber, message: ('RegularExpression Error:' + e.name + ':' + e.massage + ', Str:' + regexpStr) }); }
		});
		return regexps;
	};

	// strに完全一致する正規表現を生成
	var createRegExpPerfectMatch = function(str) {
		return new RegExp('^' + str.replace(/[.*+?^${}()|\[\]\\]/g, '\\$&') + '$');
	};

	ruleStr.split('\n').forEach(function(line, i) {
		var parsed = line.split(/\s+/);
		var matchData;
		var rule;
		if ( parsed.length >= 3 && (matchData = parsed[0].match(/^match(|_all)$/i)) ) {  // 一致
			rule = { tag: parsed[1], regexps: parsed.slice(2).map(createRegExpPerfectMatch) };
		} else if ( parsed.length >= 3 && (matchData = parsed[0].match(/^pattern(|_all)$/i)) ) { // 正規表現
			var regexps = createRegExpFromStrAry(parsed.slice(2), i + 1);
			rule = { tag: parsed[1], regexps: regexps };
		} else if ( parsed.length >= 2 && parsed[0].match(/^private$/i) ) {                     // 非公開タグ
			privateRule.push.apply(privateRule, parsed.slice(1));
			return;
		} else if ( line.match(/^\s*$|^\s*#/) ) {                                               // 空行 or コメント行
			return;
		} else {
			errors.push({ lineNumber: (i+1), message: ('CommandError:Invalid Command or Too Few Arguments, Str:' + line) });
			return;
		}

		Array.prototype.push.call(matchData[1].length === 0 ? patternRule : patternAllRule, rule);
	});
	return { privateRule: privateRule, patternRule: patternRule, patternAllRule: patternAllRule, errors: errors };
};

// matchDataの配列を渡すと文中の~数字をそれで置き換える
var replaceWithMatch = function(input, matchData) {
	return input.split(/(~\d)/).map(function(str) {
		var match = str.match(/^~(\d)/);
		if(match) { return matchData[parseInt(match[1])] || ''; }
		return str;
	}).join('');
};

// 設定画面の生成・消去
var toggleSettingsView = function() {
	// すでに存在していたなら消去
	var settingsView = document.querySelector('#autotag-settings-view');
	if (settingsView) { settingsView.remove(); return; }

	// 保存済みデータの取得
	var ruleStr = window.localStorage.pixivAutoTag_taggingRule || defaultRuleStr;

	// フォームの作成
	settingsView = document.createElement('form');
	settingsView.id = 'autotag-settings-view';
	settingsView.style.backgroundColor = '#FFFFFF';
	settingsView.style.marginTop    = '5px';
	settingsView.style.padding      = '10px 9px';
	settingsView.style.borderRadius = '5px';

	var templateStr  = '
タグ付けルール
<textarea id="autotag-settings-tagging-rule" cols="80" rows="10" style="height:auto;">{{:rule}}</textarea>
';
	settingsView.innerHTML = templateStr.replace('{{:rule}}', ruleStr);

	var buttonsParagraph = document.createElement('p');

	var saveButton = document.createElement('input');
	saveButton.type = 'submit';
	saveButton.className = '_button';
	saveButton.value = '保存';
	settingsView.onsubmit = function() {
		var ruleStr = document.querySelector('#autotag-settings-tagging-rule').value;
		var rule = parseRules(ruleStr);
		if (rule.errors.length === 0) {
			window.localStorage.pixivAutoTag_taggingRule = ruleStr;
			alert('保存しました');
		} else {
			alert(rule.errors.map(function(err) { return '[Error] line: ' + err.lineNumber + ', message: ' + err.message; }).join('\n'));
		}
		return false;
	};
	buttonsParagraph.appendChild(saveButton);

	var cancelButton = document.createElement('input');
	cancelButton.className = '_button';
	cancelButton.type = 'reset';
	cancelButton.value = 'キャンセル';
	// cancelButton.onclick = function() { document.querySelector('#autotag-settings-view').remove(); };
	buttonsParagraph.appendChild(cancelButton);

	settingsView.appendChild(buttonsParagraph);

	var settingsButton = document.querySelector('#autotag-settings-button');
	settingsButton.parentElement.insertBefore(settingsView, settingsButton.nextSibling);
};

// タグの自動追加関数
var autoTag = function() {
	var ruleText = window.localStorage.pixivAutoTag_taggingRule || defaultRuleStr;
	var rule = parseRules(ruleText);

	// 作品タグとタグクラウドの取得
	var tagCloud = Array.prototype.slice.call(document.querySelectorAll('section.list-container.tag-container.tag-cloud-container > ul.list-items.tag-cloud > li')).map(function(item) { return item.textContent; });
	var tagsExist = Array.prototype.concat.apply([], Array.prototype.slice.call(document.querySelectorAll('section.list-container.tag-container.work-tags-container > div > ul span.tag')).map(function(item) { return item.textContent.replace(/^\*/, '').split('/'); }));

	// 非公開タグが含まれていた場合、自動で非公開に設定
	var privateButton = document.querySelector('div.submit-container > ul > li:nth-child(2) > label > input[type="radio"]');
	if (tagsExist.some(function(tag){ return rule.privateRule.indexOf(tag) !== -1; })) {
		privateButton.checked = true;
	}

	// ブックマークタグリストの生成
	var input = document.querySelector('#input_tag');
	if (input.value.length === 0) {
		// 作品タグとタグクラウドの共通タグを抽出
		var tagsFound = tagsExist.filter(function(existTag) { return tagCloud.some(function(cloudTag){ return existTag === cloudTag; }); });

		// 付与タグリストの生成
		var tagsAdded = [];
		tagsExist.forEach(function(tag) { // それぞれの作品タグが
			rule.patternRule.forEach(function(patternRule) { // それぞれのルール文に対し
				var matchData = [];
				var foundMatchFlag = patternRule.regexps.some(function(pattern) { // いずれかのパターンに一致するか
					return (matchData = tag.match(pattern));
				});
				if (foundMatchFlag) { tagsAdded.push(replaceWithMatch(patternRule.tag, matchData)); }
			});
		});

		rule.patternAllRule.forEach(function(patternRule) { // それぞれのルール文の
			var matchData = [];
			var foundMatchFlag = patternRule.regexps.every(function(pattern) { // すべてのパターンが
				return tagsExist.some(function(tag) { return (matchData = tag.match(pattern)); }); // いずれかの作品タグに一致するか？
			});
			if (foundMatchFlag) { tagsAdded.push(replaceWithMatch(patternRule.tag, matchData)); }
		});

		// タグを消去する
		tagsFound = tagsFound.filter(function(foundTag) { return tagsAdded.indexOf('-'+foundTag) === -1; });
		tagsAdded = tagsAdded.filter(function(tag) { return !tag.match(/^-/); });

		// 重複の削除
		var uniqueAry = tagsFound.concat(tagsAdded).filter(function(elem, i, ary) { return ary.indexOf(elem) === i; }).join(' ');

		// ブックマークタグを設定する
		input.value = uniqueAry;

		// タグのハイライトを表示させる
		var keyupEvent = document.createEvent('HTMLEvents');
		keyupEvent.initEvent('keyup', true, true);
		input.dispatchEvent(keyupEvent);

		// 自動補完が終わったら、背景を緑色にして補完がされたことを示す
		input.parentNode.style.backgroundColor = '#76B6E0';
	}
};

(function() {
	// 自動タグ付けの実行
	if (window.location.href.match(/member_illust/)) {
		var ul = document.querySelector('section.list-container.tag-container.work-tags-container > div > ul');
		var func = function(fn) { (ul.childNodes.length > 0) ? autoTag() : window.setTimeout(fn, 750, fn); };
		window.setTimeout(func, 1250, func);
	} else {
		window.setTimeout(autoTag, 750);
	}

	// 設定ボタンの生成
	var settingsButton = document.createElement('button');
	settingsButton.className = '_button';
	settingsButton.style.marginLeft = '1em';
	settingsButton.id = 'autotag-settings-button';
	settingsButton.textContent = 'タグ自動化設定';
	settingsButton.onclick = toggleSettingsView;

	var target = document.querySelector('section.list-container.tag-container.work-tags-container > div > h1');
	target.parentElement.insertBefore(settingsButton, target.nextSibling);
})();
<commit_msg>enhancement: 強制上書きタグ付けボタンを追加した<commit_after>// ==UserScript==
// @name              Pixiv自動ブックマークタグ付け
// @description       Pixivのブックマークタグ付けを半自動化してくれる
// @include           http://www.pixiv.net/bookmark_add.php?type=illust&illust_id=*
// @include           http://www.pixiv.net/member_illust.php?mode=medium&illust_id=*
// @run-at            document-end
// @version           0.2.1
// ==/UserScript==

// デフォルトルール
var defaultRuleStr = 'private R-18';

// タグ入力欄
var input = document.querySelector('#input_tag');

// 設定テキストを解析し、連想配列で返す
var parseRules = function(ruleStr) {
	var patternRule    = [];
	var patternAllRule = [];
	var privateRule    = [];
	var errors         = [];

	// 正規表現を表す文字列のリストから、正規表現のリストを作成
	var createRegExpFromStrAry = function(regexpStrAry, lineNumber) {
		var regexps = [];
		regexpStrAry.forEach(function(regexpStr) {
			try { regexps.push(new RegExp(regexpStr)); }
			catch (e) { errors.push({ lineNumber: lineNumber, message: ('RegularExpression Error:' + e.name + ':' + e.massage + ', Str:' + regexpStr) }); }
		});
		return regexps;
	};

	// strに完全一致する正規表現を生成
	var createRegExpPerfectMatch = function(str) {
		return new RegExp('^' + str.replace(/[.*+?^${}()|\[\]\\]/g, '\\$&') + '$');
	};

	ruleStr.split('\n').forEach(function(line, i) {
		var parsed = line.split(/\s+/);
		var matchData;
		var rule;
		if ( parsed.length >= 3 && (matchData = parsed[0].match(/^match(|_all)$/i)) ) {  // 一致
			rule = { tag: parsed[1], regexps: parsed.slice(2).map(createRegExpPerfectMatch) };
		} else if ( parsed.length >= 3 && (matchData = parsed[0].match(/^pattern(|_all)$/i)) ) { // 正規表現
			var regexps = createRegExpFromStrAry(parsed.slice(2), i + 1);
			rule = { tag: parsed[1], regexps: regexps };
		} else if ( parsed.length >= 2 && parsed[0].match(/^private$/i) ) {                     // 非公開タグ
			privateRule.push.apply(privateRule, parsed.slice(1));
			return;
		} else if ( line.match(/^\s*$|^\s*#/) ) {                                               // 空行 or コメント行
			return;
		} else {
			errors.push({ lineNumber: (i+1), message: ('CommandError:Invalid Command or Too Few Arguments, Str:' + line) });
			return;
		}

		Array.prototype.push.call(matchData[1].length === 0 ? patternRule : patternAllRule, rule);
	});
	return { privateRule: privateRule, patternRule: patternRule, patternAllRule: patternAllRule, errors: errors };
};

// matchDataの配列を渡すと文中の~数字をそれで置き換える
var replaceWithMatch = function(input, matchData) {
	return input.split(/(~\d)/).map(function(str) {
		var match = str.match(/^~(\d)/);
		if(match) { return matchData[parseInt(match[1])] || ''; }
		return str;
	}).join('');
};

// 設定画面の生成・消去
var toggleSettingsView = function() {
	// すでに存在していたなら消去
	var settingsView = document.querySelector('#autotag-settings-view');
	if (settingsView) { settingsView.remove(); return; }

	// 保存済みデータの取得
	var ruleStr = window.localStorage.pixivAutoTag_taggingRule || defaultRuleStr;

	// フォームの作成
	settingsView = document.createElement('form');
	settingsView.id = 'autotag-settings-view';
	settingsView.style.backgroundColor = '#FFFFFF';
	settingsView.style.marginTop    = '5px';
	settingsView.style.padding      = '10px 9px';
	settingsView.style.borderRadius = '5px';

	var templateStr  = '
タグ付けルール
<textarea id="autotag-settings-tagging-rule" cols="80" rows="10" style="height:auto;">{{:rule}}</textarea>
';
	settingsView.innerHTML = templateStr.replace('{{:rule}}', ruleStr);

	var buttonsParagraph = document.createElement('p');

	var saveButton = document.createElement('input');
	saveButton.type = 'submit';
	saveButton.className = '_button';
	saveButton.value = '保存';
	settingsView.onsubmit = function() {
		var ruleStr = document.querySelector('#autotag-settings-tagging-rule').value;
		var rule = parseRules(ruleStr);
		if (rule.errors.length === 0) {
			window.localStorage.pixivAutoTag_taggingRule = ruleStr;
			alert('保存しました');
		} else {
			alert(rule.errors.map(function(err) { return '[Error] line: ' + err.lineNumber + ', message: ' + err.message; }).join('\n'));
		}
		return false;
	};
	buttonsParagraph.appendChild(saveButton);

	var cancelButton = document.createElement('input');
	cancelButton.className = '_button';
	cancelButton.type = 'reset';
	cancelButton.value = 'キャンセル';
	// cancelButton.onclick = function() { document.querySelector('#autotag-settings-view').remove(); };
	buttonsParagraph.appendChild(cancelButton);

	settingsView.appendChild(buttonsParagraph);

	var settingsButton = document.querySelector('#autotag-settings-button');
	settingsButton.parentElement.insertBefore(settingsView, settingsButton.nextSibling);
};

// タグの自動追加関数
var autoTag = function() {
	var ruleText = window.localStorage.pixivAutoTag_taggingRule || defaultRuleStr;
	var rule = parseRules(ruleText);

	// 作品タグとタグクラウドの取得
	var tagCloud = Array.prototype.slice.call(document.querySelectorAll('section.list-container.tag-container.tag-cloud-container > ul.list-items.tag-cloud > li')).map(function(item) { return item.textContent; });
	var tagsExist = Array.prototype.concat.apply([], Array.prototype.slice.call(document.querySelectorAll('section.list-container.tag-container.work-tags-container > div > ul span.tag')).map(function(item) { return item.textContent.replace(/^\*/, '').split('/'); }));

	// 非公開タグが含まれていた場合、自動で非公開に設定
	var privateButton = document.querySelector('div.submit-container > ul > li:nth-child(2) > label > input[type="radio"]');
	if (tagsExist.some(function(tag){ return rule.privateRule.indexOf(tag) !== -1; })) {
		privateButton.checked = true;
	}

	// ブックマークタグリストの生成
	if (input.value.length === 0) {
		// 作品タグとタグクラウドの共通タグを抽出
		var tagsFound = tagsExist.filter(function(existTag) { return tagCloud.some(function(cloudTag){ return existTag === cloudTag; }); });

		// 付与タグリストの生成
		var tagsAdded = [];
		tagsExist.forEach(function(tag) { // それぞれの作品タグが
			rule.patternRule.forEach(function(patternRule) { // それぞれのルール文に対し
				var matchData = [];
				var foundMatchFlag = patternRule.regexps.some(function(pattern) { // いずれかのパターンに一致するか
					return (matchData = tag.match(pattern));
				});
				if (foundMatchFlag) { tagsAdded.push(replaceWithMatch(patternRule.tag, matchData)); }
			});
		});

		rule.patternAllRule.forEach(function(patternRule) { // それぞれのルール文の
			var matchData = [];
			var foundMatchFlag = patternRule.regexps.every(function(pattern) { // すべてのパターンが
				return tagsExist.some(function(tag) { return (matchData = tag.match(pattern)); }); // いずれかの作品タグに一致するか？
			});
			if (foundMatchFlag) { tagsAdded.push(replaceWithMatch(patternRule.tag, matchData)); }
		});

		// タグを消去する
		tagsFound = tagsFound.filter(function(foundTag) { return tagsAdded.indexOf('-'+foundTag) === -1; });
		tagsAdded = tagsAdded.filter(function(tag) { return !tag.match(/^-/); });

		// 重複の削除
		var uniqueAry = tagsFound.concat(tagsAdded).filter(function(elem, i, ary) { return ary.indexOf(elem) === i; }).join(' ');

		// ブックマークタグを設定する
		input.value = uniqueAry;

		// タグのハイライトを表示させる
		var keyupEvent = document.createEvent('HTMLEvents');
		keyupEvent.initEvent('keyup', true, true);
		input.dispatchEvent(keyupEvent);

		// 自動補完が終わったら、背景を緑色にして補完がされたことを示す
		input.parentNode.style.backgroundColor = '#76B6E0';
	}
};

(function() {
	// 自動タグ付けの実行
	if (window.location.href.match(/member_illust/)) {
		var ul = document.querySelector('section.list-container.tag-container.work-tags-container > div > ul');
		var func = function(fn) { (ul.childNodes.length > 0) ? autoTag() : window.setTimeout(fn, 750, fn); };
		window.setTimeout(func, 1250, func);
	} else {
		window.setTimeout(autoTag, 750);
	}

	// 設定ボタンの生成
	var settingsButton = document.createElement('button');
	settingsButton.className = '_button';
	settingsButton.style.marginLeft = '1em';
	settingsButton.id = 'autotag-settings-button';
	settingsButton.textContent = 'タグ自動化設定';
	settingsButton.addEventListener('click', toggleSettingsView, false);

	var target = document.querySelector('section.list-container.tag-container.work-tags-container > div > h1');
	target.parentElement.insertBefore(settingsButton, target.nextSibling);

	// タグ付けボタンの生成
	var autoTagButton = document.createElement('button');
	autoTagButton.className = '_button';
	autoTagButton.style.marginLeft = '0.25em';
	autoTagButton.id = 'autotag-button';
	autoTagButton.textContent = '上書きタグ付け';
	autoTagButton.addEventListener('click', function() { input.value = ''; autoTag(); }, false);
	target.parentElement.insertBefore(autoTagButton, settingsButton.nextSibling);
})();
<|endoftext|>