<commit_before>module.exports = {
    "workbench.action.newWindow": [
        { "command": "new_window" }
    ],
    "workbench.action.closeWindow": [
        { "command": "close_window" }
    ],
    "workbench.action.files.openFileFolder": [
        { "command": "prompt_open" }
    ],
    "workbench.files.action.openPreviousWorkingFile": [
        { "command": "reopen_last_file" },
        { "keys": ["super+shift+["], "command": "prev_view" },
        { "keys": ["super+alt+left"], "command": "prev_view" },
    ],
    "workbench.files.action.openNextWorkingFile": [
        { "keys": ["super+shift+]"], "command": "next_view" },
        { "keys": ["super+alt+right"], "command": "next_view" },
    ],
    "workbench.files.action.newUntitledFile": [
        { "keys": ["super+n"], "command": "new_file" }
    ],
    "workbench.action.files.save": [
        { "keys": ["super+s"], "command": "save" }
    ],
    "workbench.action.files.saveAs": [
        { "keys": ["super+shift+s"], "command": "prompt_save_as" }
    ],
    "workbench.action.files.saveAll": [
        { "keys": ["super+alt+s"], "command": "save_all" }
    ],
    "workbench.action.files.closeFile": [
        { "keys": ["super+w"], "command": "close" },
        { "keys": ["super+k", "super+down"], "command": "close_pane" },
    ],
    "workbench.action.files.closeAllFiles": [],
    "workbench.action.toggleSidebarVisibility": [
        { "keys": ["super+k", "super+b"], "command": "toggle_side_bar" }
    ],
    "workbench.action.toggleFullScreen": [
        { "keys": ["super+ctrl+f"], "command": "toggle_full_screen" }
    ],
    "cursorUndo": [
        { "keys": ["super+u"], "command": "soft_undo" }
    ],
    "scrollLineUp": [
        { "keys": ["ctrl+alt+up"], "command": "scroll_lines", "args": {"amount": 1.0} }
    ],
    "scrollLineDown": [
        { "keys": ["ctrl+alt+up"], "command": "scroll_lines", "args": {"amount": -1.0} }
    ],
    "hideSuggestWidget": [
        { "command": "hide_auto_complete", "context":
            [
                { "key": "auto_complete_visible", "operator": "equal", "operand": true }
            ]
	    }
    ],
    "editor.action.indentLines": [
        { "command": "indent" }
    ],
    "editor.action.outdentLines": [
        { "command": "unindent" }
    ],
    "tab": [
        { "command": "insert_best_completion", "args": {"default": "\t", "exact": true} },
        { "command": "indent", "context": [
			    { "key": "text", "operator": "regex_contains", "operand": "\n" }
		    ]
        },
        { "keys": ["shift+tab"], "command": "insert", "args": {"characters": "\t"} },
    ],
    "jumpToNextSnippetPlaceholder": [
        { "command": "next_field", "context":
            [
                { "key": "has_next_field", "operator": "equal", "operand": true }
            ]
	    }
    ],
    "acceptSelectedSuggestion": [
        { "command": "commit_completion", "context":
            [
                { "key": "auto_complete_visible" },
                { "key": "setting.auto_complete_commit_on_tab" }
            ]
        },
        { "command": "commit_completion", "context":
            [
                { "key": "auto_complete_visible" },
                { "key": "setting.auto_complete_commit_on_tab", "operand": false }
            ]
        },
    ],
    "outdent": [
        	{ "command": "unindent", "context":
		[
			{ "key": "setting.shift_tab_unindent", "operator": "equal", "operand": true }
		]
	},
    ],
    "jumpToPrevSnippetPlaceholder": [
        	{ "command": "prev_field", "context":
		[
			{ "operator": "equal", "operand": true }
		]
	},
    ],
    "workbench.action.gotoLine": [
        { "command": "show_overlay", "args": {"overlay": "goto", "text": ":"} },
    ],
    "workbench.action.quickOpen": [
        { "command": "show_overlay", "args": {"overlay": "goto", "show_files": true} },
        { "command": "show_overlay", "args": {"overlay": "goto", "show_files": true} },
    ],
    "workbench.action.showCommands": [
        { "command": "show_overlay", "args": {"overlay": "command_palette"} },
    ],
    "workbench.action.gotoSymbol": [
        { "command": "show_overlay", "args": {"overlay": "goto", "text": "@"} },
    ],
    "editor.action.goToDeclaration": [
        { "command": "goto_definition" },
	    { "command": "goto_definition" },
    ],
    "workbench.action.navigateBack": [
        { "command": "jump_back" },
    ],
    "workbench.action.navigateForward": [
        { "command": "jump_forward" },
    ],
    "actions.find": [
        { "command": "show_panel", "args": {"panel": "find", "reverse": false} },
    ],
    "editor.action.nextMatchFindAction": [
        { "command": "find_next" },
        { "command": "next_result" },
    ],
    "editor.action.previousMatchFindAction": [
        { "keys": ["super+shift+g"], "command": "find_prev" },
        { "keys": ["shift+f4"], "command": "prev_result" },
    ],
    "workbench.view.search": [
        { "command": "show_panel", "args": {"panel": "find_in_files"} },
    ],
    "editor.action.moveLinesUpAction": [
        { "command": "swap_line_up" },
    ],
    "editor.action.moveLinesDownAction": [
        { "command": "swap_line_down" },
    ],
    "editor.action.commentLine": [
        { "command": "toggle_comment", "args": { "block": false } },
	    { "command": "toggle_comment", "args": { "block": true } },
    ],
    "editor.action.copyLinesUpAction": [
        // this isn't a perfect port - duplicate_line will not add \n, copyLinesUpAction will
        { "command": "duplicate_line" },
    ],
    "editor.action.triggerSuggest": [
        { "command": "auto_complete" },
    ],
    "workbench.action.splitEditor": [
        { "command": "new_pane" },
    ],
    "editor.fold": [
        	{ "command": "fold" },
    ],
    "editor.unfold": [
        	{ "command": "unfold" },
    ],
    "editor.foldLevel1": [
        { "command": "fold_by_level", "args": {"level": 1} },
    ],
    "editor.foldLevel2": [
        { "command": "fold_by_level", "args": {"level": 2} },
    ],
    "editor.foldLevel3": [
        { "command": "fold_by_level", "args": {"level": 3} },
    ],
    "editor.foldLevel4": [
        { "command": "fold_by_level", "args": {"level": 4} },
    ],
    "editor.foldLevel5": [
        { "command": "fold_by_level", "args": {"level": 5} },
    ],
    "editor.unfoldAll": [
        { "command": "unfold_all" },
	    { "command": "unfold_all" },
    ],
    "toggleFindRegex": [
        { "command": "toggle_regex", "context":
            [
                { "key": "setting.is_widget", "operator": "equal", "operand": true }
            ]
        },
    ],
    "toggleFindCaseSensitive": [
        { "command": "toggle_case_sensitive", "context":
            [
                { "key": "setting.is_widget", "operator": "equal", "operand": true }
            ]
        },
    ],
    "toggleFindWholeWord": [
        { "command": "toggle_whole_word", "context":
            [
                { "key": "setting.is_widget", "operator": "equal", "operand": true }
            ]
        },
    ],
    "editor.action.showContextMenu": [
        { "command": "context_menu" },
    ]
};<commit_msg>insertCursorAtEndOfEachLineSelected command binding<commit_after>module.exports = {
    "workbench.action.newWindow": [
        { "command": "new_window" }
    ],
    "workbench.action.closeWindow": [
        { "command": "close_window" }
    ],
    "workbench.action.files.openFileFolder": [
        { "command": "prompt_open" }
    ],
    "workbench.files.action.openPreviousWorkingFile": [
        { "command": "reopen_last_file" },
        { "keys": ["super+shift+["], "command": "prev_view" },
        { "keys": ["super+alt+left"], "command": "prev_view" },
    ],
    "workbench.files.action.openNextWorkingFile": [
        { "keys": ["super+shift+]"], "command": "next_view" },
        { "keys": ["super+alt+right"], "command": "next_view" },
    ],
    "workbench.files.action.newUntitledFile": [
        { "keys": ["super+n"], "command": "new_file" }
    ],
    "workbench.action.files.save": [
        { "keys": ["super+s"], "command": "save" }
    ],
    "workbench.action.files.saveAs": [
        { "keys": ["super+shift+s"], "command": "prompt_save_as" }
    ],
    "workbench.action.files.saveAll": [
        { "keys": ["super+alt+s"], "command": "save_all" }
    ],
    "workbench.action.files.closeFile": [
        { "keys": ["super+w"], "command": "close" },
        { "keys": ["super+k", "super+down"], "command": "close_pane" },
    ],
    "workbench.action.files.closeAllFiles": [],
    "workbench.action.toggleSidebarVisibility": [
        { "keys": ["super+k", "super+b"], "command": "toggle_side_bar" }
    ],
    "workbench.action.toggleFullScreen": [
        { "keys": ["super+ctrl+f"], "command": "toggle_full_screen" }
    ],
    "cursorUndo": [
        { "keys": ["super+u"], "command": "soft_undo" }
    ],
    "scrollLineUp": [
        { "keys": ["ctrl+alt+up"], "command": "scroll_lines", "args": {"amount": 1.0} }
    ],
    "scrollLineDown": [
        { "keys": ["ctrl+alt+up"], "command": "scroll_lines", "args": {"amount": -1.0} }
    ],
    "hideSuggestWidget": [
        { "command": "hide_auto_complete", "context":
            [
                { "key": "auto_complete_visible", "operator": "equal", "operand": true }
            ]
	    }
    ],
    "editor.action.indentLines": [
        { "command": "indent" }
    ],
    "editor.action.outdentLines": [
        { "command": "unindent" }
    ],
    "tab": [
        { "command": "insert_best_completion", "args": {"default": "\t", "exact": true} },
        { "command": "indent", "context": [
			    { "key": "text", "operator": "regex_contains", "operand": "\n" }
		    ]
        },
        { "keys": ["shift+tab"], "command": "insert", "args": {"characters": "\t"} },
    ],
    "jumpToNextSnippetPlaceholder": [
        { "command": "next_field", "context":
            [
                { "key": "has_next_field", "operator": "equal", "operand": true }
            ]
	    }
    ],
    "acceptSelectedSuggestion": [
        { "command": "commit_completion", "context":
            [
                { "key": "auto_complete_visible" },
                { "key": "setting.auto_complete_commit_on_tab" }
            ]
        },
        { "command": "commit_completion", "context":
            [
                { "key": "auto_complete_visible" },
                { "key": "setting.auto_complete_commit_on_tab", "operand": false }
            ]
        },
    ],
    "outdent": [
        	{ "command": "unindent", "context":
		[
			{ "key": "setting.shift_tab_unindent", "operator": "equal", "operand": true }
		]
	},
    ],
    "jumpToPrevSnippetPlaceholder": [
        	{ "command": "prev_field", "context":
		[
			{ "operator": "equal", "operand": true }
		]
	},
    ],
    "workbench.action.gotoLine": [
        { "command": "show_overlay", "args": {"overlay": "goto", "text": ":"} },
    ],
    "workbench.action.quickOpen": [
        { "command": "show_overlay", "args": {"overlay": "goto", "show_files": true} },
        { "command": "show_overlay", "args": {"overlay": "goto", "show_files": true} },
    ],
    "workbench.action.showCommands": [
        { "command": "show_overlay", "args": {"overlay": "command_palette"} },
    ],
    "workbench.action.gotoSymbol": [
        { "command": "show_overlay", "args": {"overlay": "goto", "text": "@"} },
    ],
    "editor.action.goToDeclaration": [
        { "command": "goto_definition" },
	    { "command": "goto_definition" },
    ],
    "workbench.action.navigateBack": [
        { "command": "jump_back" },
    ],
    "workbench.action.navigateForward": [
        { "command": "jump_forward" },
    ],
    "actions.find": [
        { "command": "show_panel", "args": {"panel": "find", "reverse": false} },
    ],
    "editor.action.nextMatchFindAction": [
        { "command": "find_next" },
        { "command": "next_result" },
    ],
    "editor.action.previousMatchFindAction": [
        { "keys": ["super+shift+g"], "command": "find_prev" },
        { "keys": ["shift+f4"], "command": "prev_result" },
    ],
    "workbench.view.search": [
        { "command": "show_panel", "args": {"panel": "find_in_files"} },
    ],
    "editor.action.moveLinesUpAction": [
        { "command": "swap_line_up" },
    ],
    "editor.action.moveLinesDownAction": [
        { "command": "swap_line_down" },
    ],
    "editor.action.commentLine": [
        { "command": "toggle_comment", "args": { "block": false } },
	    { "command": "toggle_comment", "args": { "block": true } },
    ],
    "editor.action.copyLinesUpAction": [
        // this isn't a perfect port - duplicate_line will not add \n, copyLinesUpAction will
        { "command": "duplicate_line" },
    ],
    "editor.action.triggerSuggest": [
        { "command": "auto_complete" },
    ],
    "workbench.action.splitEditor": [
        { "command": "new_pane" },
    ],
    "editor.fold": [
        	{ "command": "fold" },
    ],
    "editor.unfold": [
        	{ "command": "unfold" },
    ],
    "editor.foldLevel1": [
        { "command": "fold_by_level", "args": {"level": 1} },
    ],
    "editor.foldLevel2": [
        { "command": "fold_by_level", "args": {"level": 2} },
    ],
    "editor.foldLevel3": [
        { "command": "fold_by_level", "args": {"level": 3} },
    ],
    "editor.foldLevel4": [
        { "command": "fold_by_level", "args": {"level": 4} },
    ],
    "editor.foldLevel5": [
        { "command": "fold_by_level", "args": {"level": 5} },
    ],
    "editor.unfoldAll": [
        { "command": "unfold_all" },
	    { "command": "unfold_all" },
    ],
    "toggleFindRegex": [
        { "command": "toggle_regex", "context":
            [
                { "key": "setting.is_widget", "operator": "equal", "operand": true }
            ]
        },
    ],
    "toggleFindCaseSensitive": [
        { "command": "toggle_case_sensitive", "context":
            [
                { "key": "setting.is_widget", "operator": "equal", "operand": true }
            ]
        },
    ],
    "toggleFindWholeWord": [
        { "command": "toggle_whole_word", "context":
            [
                { "key": "setting.is_widget", "operator": "equal", "operand": true }
            ]
        },
    ],
    "editor.action.showContextMenu": [
        { "command": "context_menu" },
    ],
    "editor.action.insertCursorAtEndOfEachLineSelected" : [
        { "keys": ["shift+ctrl+l"], "command": "split_selection_into_lines" }
    ]
};<|endoftext|>


<commit_before>import { call } from 'redux-saga/effects'

import dbModule from './firestore'

describe('firestore', () => {
  let doc, collection, context

  beforeEach(() => {
    doc = {
      get: jest.fn()
    }
    collection = {
      doc: jest.fn(() => doc),
      get: jest.fn()
    }
    context = {
      _getCollection: jest.fn(() => collection)
    }
  })

  afterEach(() => {
    expect.hasAssertions()
  })

  describe('getCollection(collectionRef)', () => {
    it('works', () => {
      const collectionRef = 'skddksl'
      const val = 'asd'
      const result = {
        data: jest.fn(() => val),
        id: val
      }
      const response = [result, result]

      const iterator = dbModule.getCollection.call(context, collectionRef)

      expect(iterator.next().value)
        .toEqual(call([collection, collection.get]))

      expect(context._getCollection.mock.calls.length).toBe(1)
      expect(context._getCollection.mock.calls[0]).toEqual([collectionRef])

      expect(iterator.next(response)).toEqual({
        done: true,
        value: response
      })
    })
  })

  describe('getDocument(collectionRef, docRef)', () => {
    it('works', () => {
      const collectionRef = 'skddksl'
      const docRef = 'skddksld'
      const val = 'jqdqkld'
      const result = {
        data: jest.fn(() => val),
        id: 0
      }
      const iterator = dbModule.getDocument.call(context, collectionRef, docRef)

      expect(iterator.next().value)
        .toEqual(call([doc, doc.get]))

      expect(context._getCollection.mock.calls.length).toBe(1)
      expect(context._getCollection.mock.calls[0]).toEqual([collectionRef])

      expect(iterator.next(result)).toEqual({
        done: true,
        value: result
      })
    })
  })
})
<commit_msg>Rename dbModule -> firestoreModule<commit_after>import { call } from 'redux-saga/effects'

import firestoreModule from './firestore'

describe('firestore', () => {
  let doc, collection, context

  beforeEach(() => {
    doc = {
      get: jest.fn()
    }
    collection = {
      doc: jest.fn(() => doc),
      get: jest.fn()
    }
    context = {
      _getCollection: jest.fn(() => collection)
    }
  })

  afterEach(() => {
    expect.hasAssertions()
  })

  describe('getCollection(collectionRef)', () => {
    it('works', () => {
      const collectionRef = 'skddksl'
      const val = 'asd'
      const result = {
        data: jest.fn(() => val),
        id: val
      }
      const response = [result, result]

      const iterator = firestoreModule.getCollection.call(context, collectionRef)

      expect(iterator.next().value)
        .toEqual(call([collection, collection.get]))

      expect(context._getCollection.mock.calls.length).toBe(1)
      expect(context._getCollection.mock.calls[0]).toEqual([collectionRef])

      expect(iterator.next(response)).toEqual({
        done: true,
        value: response
      })
    })
  })

  describe('getDocument(collectionRef, docRef)', () => {
    it('works', () => {
      const collectionRef = 'skddksl'
      const docRef = 'skddksld'
      const val = 'jqdqkld'
      const result = {
        data: jest.fn(() => val),
        id: 0
      }
      const iterator = firestoreModule.getDocument.call(context, collectionRef, docRef)

      expect(iterator.next().value)
        .toEqual(call([doc, doc.get]))

      expect(context._getCollection.mock.calls.length).toBe(1)
      expect(context._getCollection.mock.calls[0]).toEqual([collectionRef])

      expect(iterator.next(result)).toEqual({
        done: true,
        value: result
      })
    })
  })
})
<|endoftext|>


<commit_before>var chai = require('chai'),
    expect = chai.expect,
    cb = require('../cron-builder.js');

describe('cron-builder', function () {
    var cron;

    it('defaults to "* * * * * *" when initialized without arguments', function () {
        cron = new cb();
        expect(cron.expression.minute).to.eql(['*']);
        expect(cron.expression.hour).to.eql(['*']);
        expect(cron.expression.dayOfTheMonth).to.eql(['*']);
        expect(cron.expression.monthOfTheYear).to.eql(['*']);
        expect(cron.expression.dayOfTheWeek).to.eql(['*']);
        expect(cron.expression.year).to.eql(['*']);
    });

    it('returns a working cron expression when calling .build()', function () {
        expect(cron.build()).to.equal('* * * * * *');
    });

    it('sets a single value', function () {
        cron = new cb();
        expect(cron.set(['5'], 'hour')).to.equal('5');
        expect(cron.build()).to.equal('* 5 * * * *');
    });

    it('sets multiple values at once', function () {
        cron = new cb();
        expect(cron.set(['0', '10', '20', '30', '40', '50'], 'minute')).to.equal('0,10,20,30,40,50');
        expect(cron.build()).to.equal('0,10,20,30,40,50 * * * * *');
    });

    it('sets a range', function () {
        cron = new cb();
        expect(cron.set(['5-7'], 'dayOfTheWeek')).to.equal('5-7');
        expect(cron.build()).to.equal('* * * * 5-7 *');
    });

    it('multiple sets build the cron string accurately', function () {
        cron = new cb();
        cron.set(['10', '30', '50'], 'minute');
        cron.set(['6', '18'], 'hour');
        cron.set(['1', '15'], 'dayOfTheMonth');
        cron.set(['1-5'], 'dayOfTheWeek');
        cron.set(['2015-2025'], 'year');
        expect(cron.build()).to.equal('10,30,50 6,18 1,15 * 1-5 2015-2025');
    });

    it('validates against setting an incorrect measureOfTime', function () {
        cron = new cb();
        expect(function () { cron.set(['5'], 'minutes') }).to.throw(Error);
    });

    it('validates against setting a value that is not an Array', function () {
        cron = new cb();
        expect(function () { cron.set('10', 'hour') }).to.throw(Error);
    });

    it('validates against setting a value that is not a number or range of numbers', function () {
        cron = new cb();
        expect(function () { cron.set(['!'], 'year') }).to.throw(Error);
    });

    describe('validates against setting values outside the valid range', function () {
        it('validates against values too low', function () {
            cron = new cb();
            expect(function () { cron.set(['0'], 'dayOfTheWeek') }).to.throw(Error);
        });

        it('validates against values too high', function () {
            cron = new cb();
            expect(function () { cron.set(['100'], 'hour') }).to.throw(Error);
        });

        it('validates against setting a range that is out of bounds', function () {
            cron = new cb();
            expect(function () { cron.set(['1834-2015'], 'year') }).to.throw(Error);

            expect(function () { cron.set(['20-60'], 'minute') }).to.throw(Error);

            expect(function () { cron.set(['12', '22-26', '15'], 'hour') }).to.throw(Error);
        });
    });

    it('gets a single value', function () {
        cron = new cb();
        cron.set(['30'], 'minute');
        expect(cron.get('minute')).to.equal('30');
    });

    it('validates against getting with an invalid measureOfTime', function () {
        cron = new cb();
        expect(function () { cron.get('hours'); }).to.throw(Error);
    });
});

//var cb = require('./cron-builder.js'),
//    test,
//    test2,
//    test2Exp;
//
//// init with default values ('* * * * * *')
//test = new cb();
//console.log('test init: ', test.build());
//
//test.addValue('3', 'minute');
//test.addValue('56', 'minute'); // test multiple values
//test.addValue('6', 'minutes'); // test spelling error
//
//test.addValue('1', 'hour');
//test.addValue('5', 'hour'); // test multiple values
//test.addValue('5', 'hour'); // test duplicates
//test.addValue('6-24', 'hour');
//
//test.addValue('26', 'dayOfTheMonth');
//
//test.addValue('7', 'monthOfTheYear');
//
//test.addValue('5', 'dayOfTheWeek');
//
//test.addValue('2016', 'year');
//
//console.log('after adding values: ', test.build());
//
//test.removeValue('6-24', 'hour');
//test.removeValue('6-24', 'hour');
//
//test.removeValue('2016', 'year');
//console.log('after removing values: ', test.build());
//
//console.log('getting minutes values: ', test.get('minute'));
//
//console.log('setting new minutes', test.set(['13', '26', '54-57'], 'minute'));
//test.set('5,6,7', 'dayOfTheMonth');
//test.set(['1-6'], 'dayoftheweek');
//
//console.log('test final build', test.build());
//
//// test with explicit values
//test2 = new cb('34 1 * *');
//
//console.log('test2 init', test2.build());
//
//test2Exp = test2.getAll();
//console.log('test2Exp', test2Exp);
//
//// validation test for too many values
//test2Exp.extraUnit = ['1'];
//console.log('error, exp too long', test2.setAll(test2Exp))
//
//// validation test for bad values while using setAll
//test2Exp = test2.getAll();
//
//
//
//console.log('test2 final build', test2.build());
<commit_msg>test for getAll<commit_after>var chai = require('chai'),
    expect = chai.expect,
    cb = require('../cron-builder.js');

describe('cron-builder', function () {
    var cron;

    it('defaults to "* * * * * *" when initialized without arguments', function () {
        cron = new cb();
        expect(cron.expression.minute).to.eql(['*']);
        expect(cron.expression.hour).to.eql(['*']);
        expect(cron.expression.dayOfTheMonth).to.eql(['*']);
        expect(cron.expression.monthOfTheYear).to.eql(['*']);
        expect(cron.expression.dayOfTheWeek).to.eql(['*']);
        expect(cron.expression.year).to.eql(['*']);
    });

    it('returns a working cron expression when calling .build()', function () {
        expect(cron.build()).to.equal('* * * * * *');
    });

    it('sets a single value', function () {
        cron = new cb();
        expect(cron.set(['5'], 'hour')).to.equal('5');
        expect(cron.build()).to.equal('* 5 * * * *');
    });

    it('sets multiple values at once', function () {
        cron = new cb();
        expect(cron.set(['0', '10', '20', '30', '40', '50'], 'minute')).to.equal('0,10,20,30,40,50');
        expect(cron.build()).to.equal('0,10,20,30,40,50 * * * * *');
    });

    it('sets a range', function () {
        cron = new cb();
        expect(cron.set(['5-7'], 'dayOfTheWeek')).to.equal('5-7');
        expect(cron.build()).to.equal('* * * * 5-7 *');
    });

    it('multiple sets build the cron string accurately', function () {
        cron = new cb();
        cron.set(['10', '30', '50'], 'minute');
        cron.set(['6', '18'], 'hour');
        cron.set(['1', '15'], 'dayOfTheMonth');
        cron.set(['1-5'], 'dayOfTheWeek');
        cron.set(['2015-2025'], 'year');
        expect(cron.build()).to.equal('10,30,50 6,18 1,15 * 1-5 2015-2025');
    });

    it('validates against setting an incorrect measureOfTime', function () {
        cron = new cb();
        expect(function () { cron.set(['5'], 'minutes') }).to.throw(Error);
    });

    it('validates against setting a value that is not an Array', function () {
        cron = new cb();
        expect(function () { cron.set('10', 'hour') }).to.throw(Error);
    });

    it('validates against setting a value that is not a number or range of numbers', function () {
        cron = new cb();
        expect(function () { cron.set(['!'], 'year') }).to.throw(Error);
    });

    describe('validates against setting values outside the valid range', function () {
        it('validates against values too low', function () {
            cron = new cb();
            expect(function () { cron.set(['0'], 'dayOfTheWeek') }).to.throw(Error);
        });

        it('validates against values too high', function () {
            cron = new cb();
            expect(function () { cron.set(['100'], 'hour') }).to.throw(Error);
        });

        it('validates against setting a range that is out of bounds', function () {
            cron = new cb();
            expect(function () { cron.set(['1834-2015'], 'year') }).to.throw(Error);

            expect(function () { cron.set(['20-60'], 'minute') }).to.throw(Error);

            expect(function () { cron.set(['12', '22-26', '15'], 'hour') }).to.throw(Error);
        });
    });

    it('gets a single value', function () {
        cron = new cb();
        cron.set(['30'], 'minute');
        expect(cron.get('minute')).to.equal('30');
    });

    it('validates against getting with an invalid measureOfTime', function () {
        cron = new cb();
        expect(function () { cron.get('hours'); }).to.throw(Error);
    });

    it('returns the entire expression object when getAll is called', function () {
        cron = new cb();
        var getAllResponse = cron.getAll();
        expect(getAllResponse).to.be.an('object');
        expect(getAllResponse).to.have.property('minute').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('hour').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('dayOfTheMonth').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('monthOfTheYear').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('dayOfTheWeek').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
        expect(getAllResponse).to.have.property('year').that.is.an('array').with.deep.property('[0]').that.deep.equals('*');
    });
});

//var cb = require('./cron-builder.js'),
//    test,
//    test2,
//    test2Exp;
//
//// init with default values ('* * * * * *')
//test = new cb();
//console.log('test init: ', test.build());
//
//test.addValue('3', 'minute');
//test.addValue('56', 'minute'); // test multiple values
//test.addValue('6', 'minutes'); // test spelling error
//
//test.addValue('1', 'hour');
//test.addValue('5', 'hour'); // test multiple values
//test.addValue('5', 'hour'); // test duplicates
//test.addValue('6-24', 'hour');
//
//test.addValue('26', 'dayOfTheMonth');
//
//test.addValue('7', 'monthOfTheYear');
//
//test.addValue('5', 'dayOfTheWeek');
//
//test.addValue('2016', 'year');
//
//console.log('after adding values: ', test.build());
//
//test.removeValue('6-24', 'hour');
//test.removeValue('6-24', 'hour');
//
//test.removeValue('2016', 'year');
//console.log('after removing values: ', test.build());
//
//console.log('getting minutes values: ', test.get('minute'));
//
//console.log('setting new minutes', test.set(['13', '26', '54-57'], 'minute'));
//test.set('5,6,7', 'dayOfTheMonth');
//test.set(['1-6'], 'dayoftheweek');
//
//console.log('test final build', test.build());
//
//// test with explicit values
//test2 = new cb('34 1 * *');
//
//console.log('test2 init', test2.build());
//
//test2Exp = test2.getAll();
//console.log('test2Exp', test2Exp);
//
//// validation test for too many values
//test2Exp.extraUnit = ['1'];
//console.log('error, exp too long', test2.setAll(test2Exp))
//
//// validation test for bad values while using setAll
//test2Exp = test2.getAll();
//
//
//
//console.log('test2 final build', test2.build());
<|endoftext|>


<commit_before>
/*
 * run all tests
 */

require('./cache.js');
require('./model.js');
require('./datasources/memoryDS.js');
require('./relations.js');

// tests require r/w access to jsonData.json file
require('./datasources/jsonFileDS.js');

// behaviours test
require('./behaviours/orderable.js');
require('./behaviours/tree.js');

// tests require filesystem
// require('./datasources/fileSystemDS.js');

// test require connection to mongodb
// require('./datasources/mongoDS.js');

// test require connection to elasticSearch
// require('./datasources/elasticSearchDS.js');<commit_msg>added: tests for travis<commit_after>
/*
 * run all tests
 */

require('./cache.js');
require('./model.js');
require('./datasources/memoryDS.js');
require('./relations.js');

// tests require r/w access to jsonData.json file
require('./datasources/jsonFileDS.js');

// behaviours test
require('./behaviours/orderable.js');
require('./behaviours/tree.js');

// tests require filesystem
require('./datasources/fileSystemDS.js');

// test require connection to mongodb
// require('./datasources/mongoDS.js');

// test require connection to elasticSearch
require('./datasources/elasticSearchDS.js');<|endoftext|>


<commit_before>const chai = require('chai');
const expect = chai.expect;
const sinon  = require('sinon');

const kindOfRegularResponse = require('./fake-api/kind-of-regular-response.json');

const SuperRepo = require('../lib/index.js');
const defaultConfiguration = {
    storage: 'LOCAL_VARIABLE',
    name: 'test',
    outOfDateAfter: 3 * 1000, // 3 seconds
    request: () => new Promise(resolve => resolve(kindOfRegularResponse))
};

describe('Library import', function() {
    it('Should make SuperRepo instance available.', function() {
        expect(new SuperRepo(defaultConfiguration)).to.be.an.instanceof(SuperRepo);
    });
});

describe('Data Management', () => {
    var repository;

    before(() => {
        repository = new SuperRepo(defaultConfiguration);
    });

    it('Should resolve to the server-side data', done => {
        repository.getData().then( result => {
            expect(result).to.equal(kindOfRegularResponse);
        }).then(done, done);
    });

    it('Should resolve the same data, no matter if it is taken from cache or from a network request', done => {
        repository.getData().then( () => {
            repository.getData().then( () => {

                repository.getData().then( result => {
                    expect(result).to.equal(kindOfRegularResponse);
                }).then(done, done);
            });
        });
    });

    it('Should do a network request only once', done => {
        var networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: 60 * 1000, // 1 min
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        repo.getData().then( () => {
            repo.getData().then( () => {

                repo.getData().then( result => {
                    expect(networkRequestsCount).to.equal(1);
                }).then(done, done);

            });
        });
    });

    it('Should wait if there is a Promise pending and should NOT fire another one', done => {
        let networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: 60 * 1000, // 1 min
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve =>
                    setTimeout(() => resolve(kindOfRegularResponse), 1000)
                );
            }
        });

        repo.getData();
        repo.getData();
        repo.getData();

        repo.getData().then( result => {
            expect(networkRequestsCount).to.equal(1);
        }).then(done, done);
    });

});

describe('Data Sync', () => {
    var clock;

    beforeEach(() => {
        clock = sinon.useFakeTimers();
    });
    afterEach(() => {
        clock.restore();
    });

    it('Should initiate a background data sync process that fires a network request as soon as the data gets out of date. Initially, data is outdated, therefore, the process should start with a network request. ', done => {
        const TIMEFRAME = 60 * 1000; // 1 min
        let networkRequestsCount = 0;

        const repository = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: TIMEFRAME,
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        expect(networkRequestsCount).to.equal(0);

        repository.initSyncer().then( () => {
            expect(networkRequestsCount).to.equal(1);

            clock.tick(TIMEFRAME - 1);
            expect(networkRequestsCount).to.equal(1);

            clock.tick(1);
            expect(networkRequestsCount).to.equal(2);

            clock.tick(TIMEFRAME);
            expect(networkRequestsCount).to.equal(3);

            clock.tick(5 * TIMEFRAME);
            expect(networkRequestsCount).to.equal(8);
        }).then(done, done);
    });

    it('Should initiate a background data sync process that fires a network request as soon as the data gets out of date. Initially, data is NOT outdated, therefore, the process should NOT start with a network request.', done => {
        const TIMEFRAME = 60 * 1000; // 1 min
        let networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: TIMEFRAME,
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        repo.getData().then(() => {

            expect(networkRequestsCount).to.equal(1);

            repo.initSyncer().then( () => {
                expect(networkRequestsCount).to.equal(1);

                clock.tick(TIMEFRAME - 1);

                expect(networkRequestsCount).to.equal(1);

                clock.tick(1);
                expect(networkRequestsCount).to.equal(2);

                clock.tick(TIMEFRAME);
                expect(networkRequestsCount).to.equal(3);

                clock.tick(10 * TIMEFRAME);
                expect(networkRequestsCount).to.equal(13);
            }).then(done, done);

        });
    });
});
<commit_msg>Add: test to cover the case where there is delay between getting the data and initiating the sync process<commit_after>const chai = require('chai');
const expect = chai.expect;
const sinon  = require('sinon');

const kindOfRegularResponse = require('./fake-api/kind-of-regular-response.json');

const SuperRepo = require('../lib/index.js');
const defaultConfiguration = {
    storage: 'LOCAL_VARIABLE',
    name: 'test',
    outOfDateAfter: 3 * 1000, // 3 seconds
    request: () => new Promise(resolve => resolve(kindOfRegularResponse))
};

describe('Library import', function() {
    it('Should make SuperRepo instance available.', function() {
        expect(new SuperRepo(defaultConfiguration)).to.be.an.instanceof(SuperRepo);
    });
});

describe('Data Management', () => {
    var repository;

    before(() => {
        repository = new SuperRepo(defaultConfiguration);
    });

    it('Should resolve to the server-side data', done => {
        repository.getData().then( result => {
            expect(result).to.equal(kindOfRegularResponse);
        }).then(done, done);
    });

    it('Should resolve the same data, no matter if it is taken from cache or from a network request', done => {
        repository.getData().then( () => {
            repository.getData().then( () => {

                repository.getData().then( result => {
                    expect(result).to.equal(kindOfRegularResponse);
                }).then(done, done);
            });
        });
    });

    it('Should do a network request only once', done => {
        var networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: 60 * 1000, // 1 min
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        repo.getData().then( () => {
            repo.getData().then( () => {

                repo.getData().then( result => {
                    expect(networkRequestsCount).to.equal(1);
                }).then(done, done);

            });
        });
    });

    it('Should wait if there is a Promise pending and should NOT fire another one', done => {
        let networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: 60 * 1000, // 1 min
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve =>
                    setTimeout(() => resolve(kindOfRegularResponse), 1000)
                );
            }
        });

        repo.getData();
        repo.getData();
        repo.getData();

        repo.getData().then( result => {
            expect(networkRequestsCount).to.equal(1);
        }).then(done, done);
    });

});

describe('Data Sync', () => {
    var clock;

    beforeEach(() => {
        clock = sinon.useFakeTimers();
    });
    afterEach(() => {
        clock.restore();
    });

    it('Should initiate a background data sync process that fires a network request as soon as the data gets out of date. Initially, data is outdated, therefore, the process should start with a network request. ', done => {
        const TIMEFRAME = 60 * 1000; // 1 min
        let networkRequestsCount = 0;

        const repository = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: TIMEFRAME,
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        expect(networkRequestsCount).to.equal(0);

        repository.initSyncer().then( () => {
            expect(networkRequestsCount).to.equal(1);

            clock.tick(TIMEFRAME - 1);
            expect(networkRequestsCount).to.equal(1);

            clock.tick(1);
            expect(networkRequestsCount).to.equal(2);

            clock.tick(TIMEFRAME);
            expect(networkRequestsCount).to.equal(3);

            clock.tick(5 * TIMEFRAME);
            expect(networkRequestsCount).to.equal(8);
        }).then(done, done);
    });

    it('Should initiate a background data sync process that fires a network request as soon as the data gets out of date. Initially, data is NOT outdated, therefore, the process should NOT start with a network request. Case: there is NO delay between getting the data and initiating the sync process.', done => {
        const TIMEFRAME = 60 * 1000; // 1 min
        let networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: TIMEFRAME,
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        repo.getData().then(() => {

            expect(networkRequestsCount).to.equal(1);

            repo.initSyncer().then( () => {
                expect(networkRequestsCount).to.equal(1);

                clock.tick(TIMEFRAME - 1);

                expect(networkRequestsCount).to.equal(1);

                clock.tick(1);
                expect(networkRequestsCount).to.equal(2);

                clock.tick(TIMEFRAME);
                expect(networkRequestsCount).to.equal(3);

                clock.tick(10 * TIMEFRAME);
                expect(networkRequestsCount).to.equal(13);
            }).then(done, done);

        });
    });

    it('Should initiate a background data sync process that fires a network request as soon as the data gets out of date. Initially, data is NOT outdated, therefore, the process should NOT start with a network request. Case: there is delay between getting the data and initiating the sync process.', done => {
        const TIMEFRAME = 60 * 1000; // 1 min
        let networkRequestsCount = 0;

        const repo = new SuperRepo({
            storage: 'LOCAL_VARIABLE',
            name: 'test',
            outOfDateAfter: TIMEFRAME,
            request: () => {
                networkRequestsCount++;

                return new Promise(resolve => resolve(kindOfRegularResponse));
            }
        });

        repo.getData().then(() => {
            expect(networkRequestsCount).to.equal(1);

            clock.tick(TIMEFRAME - 1000);

            repo.initSyncer().then( () => {
                expect(networkRequestsCount).to.equal(1);

                clock.tick(1000);
                expect(networkRequestsCount).to.equal(2);

                clock.tick(TIMEFRAME);
                expect(networkRequestsCount).to.equal(3);

                clock.tick(100 * TIMEFRAME);
                expect(networkRequestsCount).to.equal(103);
            }).then(done, done);
        });
    });
});
<|endoftext|>


<commit_before>var semver = require('semver')
var fs = require('fs')
var path = require('path')
var tar = require('tar')
var zlib = require('zlib')

function readJson(file, cb) {
  fs.readFile(file, 'utf-8', function (err, json) {
    if(err) return cb(err)
    try { json = JSON.parse(json) } catch (err) { return cb(err) }
    cb(null, json)
  })
}

function untar(file, dir, cb) {
  fs.createReadStream(file)
  .pipe(zlib.createGunzip())
  .on('error', function (err) {
    err.message = (
        err.message
      + '\n trying to unpack '
      + name + '@' + ver
    )
    cb(err)
  })
  .pipe(tar.Extract({path: dir}))
  .on('end', cb)
}

module.exports = function (module, vrange, opts, cb) {

  var cache = opts.cache || path.join(process.env.HOME, '.npm')
  fs.readdir(path.join(cache, module), function (err, list) {
    if(err) return cb(err)
    list = list.filter(function (e) {
      return semver.valid(e, true)
    })
    var ver = semver.maxSatisfying(list, vrange, true)
    if(!ver)
      return cb(new Error('no module satified version:' + vrange))
      var cachedir = path.join(cache, module, ver)
      var pkgfile =  path.join(cachedir,'package', 'package.json')
      readJson(pkgfile, function (err, pkg) {
        if(err && err.code == 'ENOENT') {
          //maybe we have been installing things with npmd?
          //if so, the package.json won't be unpacked.
          //unpack it and try again.
          return untar(
            path.join(cachedir, 'package.tgz'),
            cachedir,
            function (err, pkg) {
              if(err) return cb(err)
              readJson(pkgfile, function (err, pkg) {
                pkg.shasum = pkg.shasum || pkg.dist ? pkg.dist.shasum : undefined
              })
            })
        }
        cb(err, pkg)
      })
  })
}

<commit_msg>hash tarballs to get shasums!<commit_after>var semver = require('semver')
var fs = require('fs')
var path = require('path')
var tar = require('tar')
var zlib = require('zlib')
var crypto = require('crypto')

function readJson(file, cb) {
  fs.readFile(file, 'utf-8', function (err, json) {
    if(err) return cb(err)
    try { json = JSON.parse(json) } catch (err) { return cb(err) }
    cb(null, json)
  })
}

function untar(file, dir, cb) {
  fs.createReadStream(file)
  .pipe(zlib.createGunzip())
  .on('error', function (err) {
    err.message = (
        err.message
      + '\n trying to unpack '
      + name + '@' + ver
    )
    cb(err)
  })
  .pipe(tar.Extract({path: dir}))
  .on('end', cb)
}

function sha(file, cb) {
  var hash = crypto.createHash('sha1')
  fs.createReadStream(file)
  .on('data', function (d) { hash.update(d) })
  .on('end', function () { cb(null, hash.digest('hex')) })
  .on('error', cb)
}

function readJsonAndHash (cachedir, cb) {
  var pkgfile =  path.join(cachedir,'package', 'package.json')
  var pkgtarfile = path.join(cachedir, 'package.tgz')
  var err, hash, pkg
  sha(pkgtarfile, function (_err, _hash) {
    err =_err; hash = _hash; next()
  })
  readJson(pkgfile, function (_err, _pkg) {
    err = _err; pkg = _pkg; next()
  })

  function next () {
    if(err) return cb(err)
    if(hash && pkg) {
      pkg.shasum = hash
      cb(err, pkg)
    }
  }

}

module.exports = function (module, vrange, opts, cb) {

  var cache = opts.cache || path.join(process.env.HOME, '.npm')
  fs.readdir(path.join(cache, module), function (err, list) {
    if(err) return cb(err)
    list = list.filter(function (e) {
      return semver.valid(e, true)
    })
    var ver = semver.maxSatisfying(list, vrange, true)
    if(!ver)
      return cb(new Error('no module satified version:' + vrange))
      var cachedir = path.join(cache, module, ver)
    readJsonAndHash(cachedir, function (err, pkg) {
      if(err && err.code == 'ENOENT') {
        //maybe we have been installing things with npmd?
        //if so, the package.json won't be unpacked.
        //unpack it and try again.
        return untar(
          pkgtarfile,
          cachedir,
          function (err, pkg) {
            if(err) return cb(err)
            readJsonAndHash(cachedir, cb)
          })
      }
      cb(null, pkg)
    })

  })
}

<|endoftext|>


<commit_before>/* jshint node: true */
/* global describe:false, expect: false, it:false, beforeEach:false, afterEach:false */
'use strict';

var assert = require('assert');
var Markdown = require('../index.js');

describe('node-markup-markdown using custom rules', function () {

  // Empty ruleset container
  // Will be customized for each test
  var options;

  beforeEach(function () {
    options = {
      markup: {},
      rules: [],
      processors: []
    };
  });

  it('parses custom rules', function () {
    options.rules = [{
      pattern: /#[ ]*(.+)/g,
      replacement: '
$1
'
    }];

    assert.equal(Markdown.parse('# Headline H1', options), '
Headline H1
');
  });

  it('parses multiples custom rules', function () {
    options.rules = [{
      pattern: /#{3}[ ]*([^#\n]+)/g,
      replacement: '
$1
'
    }, {
      pattern: /#{2}[ ]*([^#\n]+)/g,
      replacement: '
$1
'
    }, {
      pattern: /#{1}[ ]*([^#\n]+)/g,
      replacement: '
$1
'
    }];

    assert.equal(Markdown.parse('# Headline H1\n### Headline H3', options), '
Headline H1
\n
Headline H3
');
  });

  it('parses custom inline rules', function () {
    options.rules = [{
      pattern: /\*\*([^*\n]+)\*\*/g,
      replacement: '$1'
    }, {
      pattern: /\*([^*\n]+)\*/g,
      replacement: '$1'
    }];

    assert.equal(Markdown.parse('My text with **bold** and *italic* markup', options), 'My text with bold and italic markup');
  });

  it('recogizes custom markup options', function () {
    options.markup = {
      strong: '$1',
      italic: '$1'
    };

    options.rules = [{
      pattern: /\*\*([^*\n]+)\*\*/g,
      replacement: ':strong'
    }, {
      pattern: /\*([^*\n]+)\*/g,
      replacement: ':italic'
    }];

    assert.equal(Markdown.parse('My text with **bold** and *italic* markup', options), 'My text with bold and italic markup');
  });
});

describe('node-markup-markdown using custom processors', function () {

  // Empty ruleset container
  // Will be customized for each test
  var options;

  beforeEach(function () {
    options = {
      markup: {},
      rules: [],
      processors: []
    };
  });

  it('parses custom processors', function () {
    options.processors = [
      function(line) {
        return line.replace(/\*\*([^*\n]+)\*\*/g, '$1');
      },
      function(line) {
        return line.replace(/\*([^*\n]+)\*/g, '$1');
      }
    ];

    assert.equal(Markdown.parse('My text with **bold** and\n*italic* markup', options), 'My text with bold and\nitalic markup');
  });

  it('allows to set a state for custom processors', function () {
    options.processors = [
      function(line) {
        this.counter = this.counter || 0;
        return line + this.counter++;
      }
    ];

    assert.equal(Markdown.parse('My\ntext\nwith\n**bold**\nand\n*italic*\nmarkup', options), 'My1\ntext2\nwith3\n**bold**4\nand5\n*italic*6\nmarkup7');
  });

  it('allows access to the whole text for custom processors', function () {
    options.processors = [
      function(line) {
        return this.text;
      }
    ];

    assert.equal(Markdown.parse('My\ntext\nmarkup', options), 'My\ntext\nmarkup\nMy\ntext\nmarkup\nMy\ntext\nmarkup');
  });

  it('allows access to the configuration options for custom processors', function () {
    options.processors = [
      function(line) {
        return this.options.markup.pattern + ':' + this.options.markup.replacement;
      }
    ];

    options.markup = {
      pattern: 'foo',
      replacement: 'bar'
    };

    assert.equal(Markdown.parse('test', options), 'foo:bar');
  });

});

describe('node-markup-markdown using default rules and processors', function () {

  // Empty ruleset container
  // Will be customized for each test
  var options;

  beforeEach(function () {
    options = {
      markup: {},
      rules: [],
      processors: []
    };
  });

  it('recogizes default markup overwrites', function () {
    // Overwrite custom
    options = {
      markup: {
        strong: '<foo>$1</foo>',
        emphasis: '<bar>$1</bar>'
      }
    };

    assert.equal(Markdown.parse('My text with **bold** and *italic* markup', options), 'My text with <foo>bold</foo> and <bar>italic</bar> markup');
  });
});

describe('node-markup-markdown using default options', function () {

  it('parses strong', function () {
    assert.equal(Markdown.parse('My text with **strong** markup'), 'My text with strong markup');
  });

  it('parses emphasis', function () {
    assert.equal(Markdown.parse('My text with *emphasized* markup'), 'My text with emphasized markup');
  });

  it('parses links', function () {
    assert.equal(Markdown.parse('[Link](http://example.com)'), 'Link');
  });

  it('parses anchors', function () {
    assert.equal(Markdown.parse('[Link][target]'), 'Link');
  });

  it('parses inline code', function () {
    assert.equal(Markdown.parse('My test `code element` inline'), 'My test code element inline');
  });

  it('parses multiple inline code elements in one line', function () {
    assert.equal(Markdown.parse('My test `code element` inline followed `by another one`'), 'My test code element inline followed by another one');
  });

  it('parses code blocks', function () {
    assert.equal(Markdown.parse('My test\n```\ncode element\n\nspanning multiple lines\n```'), 'My test
\ncode element\n\nspanning multiple lines\n
');
  });

  it('parses code blocks with type', function () {
    assert.equal(Markdown.parse('My test\n```javascript\ncode element\n\nspanning multiple lines\n```'), 'My test
\ncode element\n\nspanning multiple lines\n
');
  });

  it('parses horizontal lines', function () {
    assert.equal(Markdown.parse('Test\n---\nTest\n***\nTest\n___\nTest'), 'Test
Test
Test
Test');
  });

  it('parses paragraphs', function () {
    assert.equal(Markdown.parse('# Headline\n\nParagraph\n\n# Headline'), '
Headline

Paragraph

Headline
');
  });

  it('parses table cells', function () {
    assert.equal(Markdown.parse('|Cell||Cell|'), 'Cell	Cell	');
  });

  it('parses table header cells', function () {
    assert.equal(Markdown.parse('|:Cell:||:Cell:|'), 'Cell	Cell	');
  });

  it('parses table rows', function () {
    assert.equal(Markdown.parse('||Cell||Cell||'), '
Cell	Cell
');
  });

  it('parses tables', function () {
    assert.equal(Markdown.parse('|||Cell||Cell|||'), '

Cell	Cell

');
  });

  it('parses headline H1', function () {
    assert.equal(Markdown.parse('# My text'), '
My text
');
  });

  it('parses headline H2', function () {
    assert.equal(Markdown.parse('## My text'), '
My text
');
  });

  it('parses headline H3', function () {
    assert.equal(Markdown.parse('### My text'), '
My text
');
  });

  it('parses headline H4', function () {
    assert.equal(Markdown.parse('#### My text'), '
My text
');
  });

  it('parses headline H5', function () {
    assert.equal(Markdown.parse('##### My text'), '
My text
');
  });

  it('parses headline H6', function () {
    assert.equal(Markdown.parse('###### My text'), '
My text
');
  });

  it('parses lists holding a single list item', function () {
    assert.equal(Markdown.parse('* My list item'), '

My list item

');
  });

  it('parses lists holding multiple list items', function () {
    assert.equal(Markdown.parse('* First\n* Second\n* Third'), '

First

Second

Third

');
  });

  it('parses multiple lists', function () {
    assert.equal(Markdown.parse('* First\n\n\n* First\n* Second'), '

First

First

Second

');
  });

  it('parses linebreaks', function () {
    assert.equal(Markdown.parse('My\nlinebreak'), 'My
linebreak');
  });

  it('parses spacers', function () {
    assert.equal(Markdown.parse('My\n\nlinebreak'), 'My
linebreak');
  });
});
<commit_msg>Updates tests to changed rules.<commit_after>/* jshint node: true */
/* global describe:false, expect: false, it:false, beforeEach:false, afterEach:false */
'use strict';

var assert = require('assert');
var Markdown = require('../index.js');

describe('node-markup-markdown using custom rules', function () {

  // Empty ruleset container
  // Will be customized for each test
  var options;

  beforeEach(function () {
    options = {
      markup: {},
      rules: []
    };
  });

  it('parses custom rules', function () {
    options.rules = [{
      pattern: /#[ ]*(.+)/g,
      replacement: '
$1
'
    }];

    assert.equal(Markdown.parse('# Headline H1', options), '
Headline H1
');
  });

  it('parses multiples custom rules', function () {
    options.rules = [{
      pattern: /#{3}[ ]*([^#\n]+)/g,
      replacement: '
$1
'
    }, {
      pattern: /#{2}[ ]*([^#\n]+)/g,
      replacement: '
$1
'
    }, {
      pattern: /#{1}[ ]*([^#\n]+)/g,
      replacement: '
$1
'
    }];

    assert.equal(Markdown.parse('# Headline H1\n### Headline H3', options), '
Headline H1
\n
Headline H3
');
  });

  it('parses custom inline rules', function () {
    options.rules = [{
      pattern: /\*\*([^*\n]+)\*\*/g,
      replacement: '$1'
    }, {
      pattern: /\*([^*\n]+)\*/g,
      replacement: '$1'
    }];

    assert.equal(Markdown.parse('My text with **bold** and *italic* markup', options), 'My text with bold and italic markup');
  });

  it('recogizes custom markup options', function () {
    options.markup = {
      strong: '$1',
      italic: '$1'
    };

    options.rules = [{
      pattern: /\*\*([^*\n]+)\*\*/g,
      replacement: ':strong'
    }, {
      pattern: /\*([^*\n]+)\*/g,
      replacement: ':italic'
    }];

    assert.equal(Markdown.parse('My text with **bold** and *italic* markup', options), 'My text with bold and italic markup');
  });
});

describe('node-markup-markdown using default rules and processors', function () {

  // Empty ruleset container
  // Will be customized for each test
  var options;

  beforeEach(function () {
    options = {
      markup: {},
      rules: []
    };
  });

  it('recogizes default markup overwrites', function () {
    // Overwrite custom
    options = {
      markup: {
        strong: '<foo>$1</foo>',
        emphasis: '<bar>$1</bar>'
      }
    };

    assert.equal(Markdown.parse('My text with **bold** and *italic* markup', options), 'My text with <foo>bold</foo> and <bar>italic</bar> markup');
  });
});

describe('node-markup-markdown using default options', function () {

  it('parses strong', function () {
    assert.equal(Markdown.parse('My text with **strong** markup'), 'My text with strong markup');
  });

  it('parses emphasis', function () {
    assert.equal(Markdown.parse('My text with *emphasized* markup'), 'My text with emphasized markup');
  });

  it('parses links', function () {
    assert.equal(Markdown.parse('[Link](http://example.com)'), 'Link');
  });

  it('parses anchors', function () {
    assert.equal(Markdown.parse('[Link][target]'), 'Link');
  });

  it('parses inline code', function () {
    assert.equal(Markdown.parse('My test `code element` inline'), 'My test code element inline');
  });

  it('parses multiple inline code elements in one line', function () {
    assert.equal(Markdown.parse('My test `code element` inline followed `by another one`'), 'My test code element inline followed by another one');
  });

  it('parses code blocks', function () {
    assert.equal(Markdown.parse('My test\n```\ncode element\n\nspanning multiple lines\n```'), 'My test
\ncode element\n\nspanning multiple lines\n
');
  });

  it('parses code blocks with type', function () {
    assert.equal(Markdown.parse('My test\n```javascript\ncode element\n\nspanning multiple lines\n```'), 'My test
\ncode element\n\nspanning multiple lines\n
');
  });

  it('parses horizontal lines', function () {
    assert.equal(Markdown.parse('Test\n---\nTest\n***\nTest\n___\nTest'), 'Test
Test
Test
Test');
  });

  it('parses paragraphs', function () {
    assert.equal(Markdown.parse('# Headline\n\nParagraph\n\n# Headline'), '
Headline

Paragraph

Headline
');
  });

  it('parses table cells', function () {
    assert.equal(Markdown.parse('|Cell||Cell|'), 'Cell	Cell	');
  });

  it('parses table header cells', function () {
    assert.equal(Markdown.parse('|:Cell:||:Cell:|'), 'Cell	Cell	');
  });

  it('parses table rows', function () {
    assert.equal(Markdown.parse('||Cell||Cell||'), '
Cell	Cell
');
  });

  it('parses tables', function () {
    assert.equal(Markdown.parse('|||Cell||Cell|||'), '

Cell	Cell

');
  });

  it('parses headline H1', function () {
    assert.equal(Markdown.parse('# My text'), '
My text
');
  });

  it('parses headline H2', function () {
    assert.equal(Markdown.parse('## My text'), '
My text
');
  });

  it('parses headline H3', function () {
    assert.equal(Markdown.parse('### My text'), '
My text
');
  });

  it('parses headline H4', function () {
    assert.equal(Markdown.parse('#### My text'), '
My text
');
  });

  it('parses headline H5', function () {
    assert.equal(Markdown.parse('##### My text'), '
My text
');
  });

  it('parses headline H6', function () {
    assert.equal(Markdown.parse('###### My text'), '
My text
');
  });

  it('parses lists holding a single list item', function () {
    assert.equal(Markdown.parse('* My list item'), '

My list item

');
  });

  it('parses lists holding multiple list items', function () {
    assert.equal(Markdown.parse('* First\n* Second\n* Third'), '

First

Second

Third

');
  });

  it('parses multiple lists', function () {
    assert.equal(Markdown.parse('* First\n\n\n* First\n* Second'), '

First

First

Second

');
  });

  it('parses linebreaks', function () {
    assert.equal(Markdown.parse('My\nlinebreak'), 'My
linebreak');
  });

  it('parses spacers', function () {
    assert.equal(Markdown.parse('My\n\nlinebreak'), 'My

linebreak');
  });
});
<|endoftext|>


<commit_before>import { createWriteStream, readFileSync } from 'fs';
import { basename, dirname, join } from 'path';

import test from 'ava';
import webpack from 'webpack';
import rimraf from 'rimraf';
import mkdirp from 'mkdirp';
import yauzl from 'yauzl';

import ZipPlugin from '../index';

function randomPath() {
	return join(__dirname, 'dist', String(Math.random()).slice(2));
}

function runWithOptions({ path, filename }, options) {
	return new Promise((resolve, reject) => {
		webpack({
			entry: join(__dirname, 'src', 'app'),
			bail: true,
			output: {
				path,
				filename
			},
			plugins: [
				new ZipPlugin(options)
			]
		}, (err, stats) => {
			err ? reject(err) : resolve(stats);
		});
	});
}

test('basic', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' });

	const byeJpg = readFileSync(join(out, 'subdir', 'bye.jpg'));
	const bundleJs = readFileSync(join(out, 'bundle.js'));
	const spawnedJs = readFileSync(join(out, 'spawned.js'));
	const bundleJsZip = readFileSync(join(out, 'bundle.js.zip'));

	t.truthy(byeJpg);
	t.regex(bundleJs, /var a = 'b';/);
	t.regex(spawnedJs, /var foo = 'bar';/);
	t.truthy(bundleJsZip);
});

async function unzip(zipFilePath, outDirPath) {
	const zipFile = await new Promise((resolve, reject) => {
		yauzl.open(zipFilePath, { lazyEntries: true }, (err, zipFile) => {
			err ? reject(err) : resolve(zipFile);
		});
	});

	zipFile.readEntry();

	zipFile.on('entry', entry => {
		zipFile.openReadStream(entry, (err, readStream) => {
			if (err) throw err;
			mkdirp.sync(join(outDirPath, dirname(entry.fileName)));
			const writeStream = createWriteStream(join(outDirPath, entry.fileName));
			readStream.pipe(writeStream);
			writeStream.on('close', () => zipFile.readEntry());
		});
	});

	await new Promise((resolve, reject) => {
		zipFile.on('close', resolve);
		zipFile.on('error', reject);
	});
}

test('roundtrip', async t => {
	const out = randomPath();
	const outSrc = join(out, 'src');
	const outDst = join(out, 'dst');

	await runWithOptions({ path: outSrc, filename: 'bundle.js' });

	await unzip(join(outSrc, 'bundle.js.zip'), outDst);

	t.is(Buffer.compare(
		readFileSync(join(outSrc, 'subdir', 'bye.jpg')),
		readFileSync(join(outDst, 'subdir', 'bye.jpg'))
	), 0);
	t.is(Buffer.compare(
		readFileSync(join(outSrc, 'bundle.js')),
		readFileSync(join(outDst, 'bundle.js'))
	), 0);
	t.is(Buffer.compare(
		readFileSync(join(outSrc, 'spawned.js')),
		readFileSync(join(outDst, 'spawned.js'))
	), 0);
});

async function roundtrip(options) {
	const out = randomPath();
	const outSrc = join(out, 'src');
	const outDst = join(out, 'dst');

	await runWithOptions({ path: outSrc, filename: 'bundle.js' }, options);

	await unzip(join(outSrc, 'bundle.js.zip'), outDst);

	return outDst;
}

test('exclude string', async t => {
	const out = await roundtrip({ exclude: 'spawned.js' });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.throws(() => readFileSync(join(out, 'spawned.js')));
});

test('include string', async t => {
	const out = await roundtrip({ include: 'spawned.js' });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('exclude regex', async t => {
	const out = await roundtrip({ exclude: /\.jpg$/ });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('include regex', async t => {
	const out = await roundtrip({ include: /\.js$/ });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('multiple excludes', async t => {
	const out = await roundtrip({ exclude: [/\.jpg$/, 'bundle.js'] });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('multiple includes', async t => {
	const out = await roundtrip({ include: [/\.jpg$/, 'bundle.js'] });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.throws(() => readFileSync(join(out, 'spawned.js')));
});

test('exclude overrides include', async t => {
	const out = await roundtrip({ include: [/\.jpg$/, /\.js$/], exclude: ['bundle.js'] });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('exclude dir', async t => {
	const out = await roundtrip({ exclude: 'subdir/' });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('loaders not tested for include', async t => {
	const out = await roundtrip({ include: /file/i });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.throws(() => readFileSync(join(out, 'spawned.js')));
});

test('loaders not tested for exclude', async t => {
	const out = await roundtrip({ exclude: /file/i });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('fileOptions', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, {
		fileOptions: {
			mtime: new Date('2016-01-01Z'),
			mode: 0o100664,
			forceZip64Format: true,
			compress: false,
		},
	});

	t.is(readFileSync(join(out, 'bundle.js.zip')).length, 59903);
});

test('zipOptions', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, {
		zipOptions: {
			forceZip64Format: true,
		},
	});

	t.is(readFileSync(join(out, 'bundle.js.zip')).length, 57038);
});

test('fileOptions and zipOptions', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, {
		fileOptions: {
			mtime: new Date('2015-01-01Z'),
			mode: 0o100665,
			forceZip64Format: true,
		},
		zipOptions: {
			forceZip64Format: true,
		},
	});

	t.is(readFileSync(join(out, 'bundle.js.zip')).length, 57122);
});

test('pathPrefix', async t => {
    const out = await roundtrip({ pathPrefix: 'prefix' });

    t.truthy(readFileSync(join(out, 'prefix', 'subdir', 'bye.jpg')));
    t.truthy(readFileSync(join(out, 'prefix', 'bundle.js')));
});

test('pathPrefix - throws on absolute path', async t => {
    t.throws(() => {
    	const plugin = new ZipPlugin({ pathPrefix: '/prefix' });
    	plugin.apply();
    });
});

test('naming - default options, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out });
	t.truthy(readFileSync(join(out, '[name].js.zip')), '.zip exists');
});

test('naming - default options, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' });
	t.truthy(readFileSync(join(out, 'bundle.js.zip')), '.zip exists');
});

test('naming - specified filename with .zip, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { filename: 'my_app.zip' });
	t.truthy(readFileSync(join(out, 'my_app.zip')), '.zip exists');
});

test('naming - specified filename without .zip, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { filename: 'my_app' });
	t.truthy(readFileSync(join(out, 'my_app.zip')), '.zip exists');
});

test('naming - specified filename with .zip, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { filename: 'my_app.zip' });
	t.truthy(readFileSync(join(out, 'my_app.zip')), '.zip exists');
});

test('naming - specified relative path, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: 'zip' });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified relative path with slash, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: './zip' });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified relative path with parent, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: join(out, 'bin') }, { path: '../zip' });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified absolute path, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: join(out, 'zip') });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified relative path, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: 'zip' });
	t.truthy(readFileSync(join(out, 'zip', 'bundle.js.zip')), '.zip exists');
});

test('naming - specified absolute path, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: join(out, 'zip') });
	t.truthy(readFileSync(join(out, 'zip', 'bundle.js.zip')), '.zip exists');
});

test('naming - both specified, relative, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: 'zip', filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test('naming - both specified, absolute, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: join(out, 'zip'), filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test('naming - both specified, relative, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: 'zip', filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test('naming - both specified, absolute, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: join(out, 'zip'), filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test.after(() => {
	rimraf.sync(join(__dirname, 'dist'));
});
<commit_msg>test: update zip file sizes<commit_after>import { createWriteStream, readFileSync } from 'fs';
import { basename, dirname, join } from 'path';

import test from 'ava';
import webpack from 'webpack';
import rimraf from 'rimraf';
import mkdirp from 'mkdirp';
import yauzl from 'yauzl';

import ZipPlugin from '../index';

function randomPath() {
	return join(__dirname, 'dist', String(Math.random()).slice(2));
}

function runWithOptions({ path, filename }, options) {
	return new Promise((resolve, reject) => {
		webpack({
			entry: join(__dirname, 'src', 'app'),
			bail: true,
			output: {
				path,
				filename
			},
			plugins: [
				new ZipPlugin(options)
			]
		}, (err, stats) => {
			err ? reject(err) : resolve(stats);
		});
	});
}

test('basic', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' });

	const byeJpg = readFileSync(join(out, 'subdir', 'bye.jpg'));
	const bundleJs = readFileSync(join(out, 'bundle.js'));
	const spawnedJs = readFileSync(join(out, 'spawned.js'));
	const bundleJsZip = readFileSync(join(out, 'bundle.js.zip'));

	t.truthy(byeJpg);
	t.regex(bundleJs, /var a = 'b';/);
	t.regex(spawnedJs, /var foo = 'bar';/);
	t.truthy(bundleJsZip);
});

async function unzip(zipFilePath, outDirPath) {
	const zipFile = await new Promise((resolve, reject) => {
		yauzl.open(zipFilePath, { lazyEntries: true }, (err, zipFile) => {
			err ? reject(err) : resolve(zipFile);
		});
	});

	zipFile.readEntry();

	zipFile.on('entry', entry => {
		zipFile.openReadStream(entry, (err, readStream) => {
			if (err) throw err;
			mkdirp.sync(join(outDirPath, dirname(entry.fileName)));
			const writeStream = createWriteStream(join(outDirPath, entry.fileName));
			readStream.pipe(writeStream);
			writeStream.on('close', () => zipFile.readEntry());
		});
	});

	await new Promise((resolve, reject) => {
		zipFile.on('close', resolve);
		zipFile.on('error', reject);
	});
}

test('roundtrip', async t => {
	const out = randomPath();
	const outSrc = join(out, 'src');
	const outDst = join(out, 'dst');

	await runWithOptions({ path: outSrc, filename: 'bundle.js' });

	await unzip(join(outSrc, 'bundle.js.zip'), outDst);

	t.is(Buffer.compare(
		readFileSync(join(outSrc, 'subdir', 'bye.jpg')),
		readFileSync(join(outDst, 'subdir', 'bye.jpg'))
	), 0);
	t.is(Buffer.compare(
		readFileSync(join(outSrc, 'bundle.js')),
		readFileSync(join(outDst, 'bundle.js'))
	), 0);
	t.is(Buffer.compare(
		readFileSync(join(outSrc, 'spawned.js')),
		readFileSync(join(outDst, 'spawned.js'))
	), 0);
});

async function roundtrip(options) {
	const out = randomPath();
	const outSrc = join(out, 'src');
	const outDst = join(out, 'dst');

	await runWithOptions({ path: outSrc, filename: 'bundle.js' }, options);

	await unzip(join(outSrc, 'bundle.js.zip'), outDst);

	return outDst;
}

test('exclude string', async t => {
	const out = await roundtrip({ exclude: 'spawned.js' });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.throws(() => readFileSync(join(out, 'spawned.js')));
});

test('include string', async t => {
	const out = await roundtrip({ include: 'spawned.js' });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('exclude regex', async t => {
	const out = await roundtrip({ exclude: /\.jpg$/ });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('include regex', async t => {
	const out = await roundtrip({ include: /\.js$/ });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('multiple excludes', async t => {
	const out = await roundtrip({ exclude: [/\.jpg$/, 'bundle.js'] });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('multiple includes', async t => {
	const out = await roundtrip({ include: [/\.jpg$/, 'bundle.js'] });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.throws(() => readFileSync(join(out, 'spawned.js')));
});

test('exclude overrides include', async t => {
	const out = await roundtrip({ include: [/\.jpg$/, /\.js$/], exclude: ['bundle.js'] });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('exclude dir', async t => {
	const out = await roundtrip({ exclude: 'subdir/' });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('loaders not tested for include', async t => {
	const out = await roundtrip({ include: /file/i });

	t.throws(() => readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.throws(() => readFileSync(join(out, 'bundle.js')));
	t.throws(() => readFileSync(join(out, 'spawned.js')));
});

test('loaders not tested for exclude', async t => {
	const out = await roundtrip({ exclude: /file/i });

	t.truthy(readFileSync(join(out, 'subdir', 'bye.jpg')));
	t.truthy(readFileSync(join(out, 'bundle.js')));
	t.truthy(readFileSync(join(out, 'spawned.js')));
});

test('fileOptions', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, {
		fileOptions: {
			mtime: new Date('2016-01-01Z'),
			mode: 0o100664,
			forceZip64Format: true,
			compress: false,
		},
	});

	t.is(readFileSync(join(out, 'bundle.js.zip')).length, 62146);
});

test('zipOptions', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, {
		zipOptions: {
			forceZip64Format: true,
		},
	});

	t.is(readFileSync(join(out, 'bundle.js.zip')).length, 57653);
});

test('fileOptions and zipOptions', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, {
		fileOptions: {
			mtime: new Date('2015-01-01Z'),
			mode: 0o100665,
			forceZip64Format: true,
		},
		zipOptions: {
			forceZip64Format: true,
		},
	});

	t.is(readFileSync(join(out, 'bundle.js.zip')).length, 57737);
});

test('pathPrefix', async t => {
    const out = await roundtrip({ pathPrefix: 'prefix' });

    t.truthy(readFileSync(join(out, 'prefix', 'subdir', 'bye.jpg')));
    t.truthy(readFileSync(join(out, 'prefix', 'bundle.js')));
});

test('pathPrefix - throws on absolute path', async t => {
    t.throws(() => {
    	const plugin = new ZipPlugin({ pathPrefix: '/prefix' });
    	plugin.apply();
    });
});

test('naming - default options, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out });
	t.truthy(readFileSync(join(out, '[name].js.zip')), '.zip exists');
});

test('naming - default options, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' });
	t.truthy(readFileSync(join(out, 'bundle.js.zip')), '.zip exists');
});

test('naming - specified filename with .zip, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { filename: 'my_app.zip' });
	t.truthy(readFileSync(join(out, 'my_app.zip')), '.zip exists');
});

test('naming - specified filename without .zip, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { filename: 'my_app' });
	t.truthy(readFileSync(join(out, 'my_app.zip')), '.zip exists');
});

test('naming - specified filename with .zip, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { filename: 'my_app.zip' });
	t.truthy(readFileSync(join(out, 'my_app.zip')), '.zip exists');
});

test('naming - specified relative path, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: 'zip' });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified relative path with slash, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: './zip' });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified relative path with parent, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: join(out, 'bin') }, { path: '../zip' });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified absolute path, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: join(out, 'zip') });
	t.truthy(readFileSync(join(out, 'zip', '[name].js.zip')), '.zip exists');
});

test('naming - specified relative path, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: 'zip' });
	t.truthy(readFileSync(join(out, 'zip', 'bundle.js.zip')), '.zip exists');
});

test('naming - specified absolute path, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: join(out, 'zip') });
	t.truthy(readFileSync(join(out, 'zip', 'bundle.js.zip')), '.zip exists');
});

test('naming - both specified, relative, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: 'zip', filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test('naming - both specified, absolute, no webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out }, { path: join(out, 'zip'), filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test('naming - both specified, relative, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: 'zip', filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test('naming - both specified, absolute, with webpack filename', async t => {
	const out = randomPath();
	await runWithOptions({ path: out, filename: 'bundle.js' }, { path: join(out, 'zip'), filename: 'archive' });
	t.truthy(readFileSync(join(out, 'zip', 'archive.zip')), '.zip exists');
});

test.after(() => {
	rimraf.sync(join(__dirname, 'dist'));
});
<|endoftext|>


<commit_before>/**
 * Date Functions available inside Mavo expressions
 */

(function($, val, _, $u = _.util) {

var s = {seconds: 1, minutes: 60};
s.hours  = s.minutes * 60;
s.days   = s.hours   * 24;
s.weeks  = s.days    * 7;
s.months = s.days    * 30.4368;
s.years  = s.weeks  * 52;

var numeric = {
	year: d => d.getFullYear(),
	month: d => d.getMonth() + 1,
	day: d => d.getDate(),
	weekday: d => d.getDay() || 7,
	hour: d => d.getHours(),
	minute: d => d.getMinutes(),
	second: d => d.getSeconds(),
	ms: d => d.getMilliseconds()
};

$.extend(_, {
	get $now() {
		return new Date();
	},

	$startup: new Date(), // Like $now, but doesn't update

	get $today() {
		return _.date(new Date());
	},

	year: $.extend(function() {
		return $u.dateComponent("year", ...arguments);
	}, {multiValued: true}),

	month: $.extend(function() {
		return $u.dateComponent("month", ...arguments);
	}, {multiValued: true}),

	week: () => s.weeks * 1000,

	day: $.extend(function() {
		return $u.dateComponent("day", ...arguments);
	}, {multiValued: true}),

	weekday: $.extend(function() {
		return $u.dateComponent("weekday", ...arguments);
	}, {multiValued: true}),

	hour: $.extend(function() {
		return $u.dateComponent("hour", ...arguments);
	}, {multiValued: true}),

	minute: $.extend(function() {
		return $u.dateComponent("minute", ...arguments);
	}, {multiValued: true}),

	second: $.extend(function() {
		return $u.dateComponent("second", ...arguments);
	}, {multiValued: true}),

	ms: $.extend(function() {
		return $u.dateComponent("ms", ...arguments);
	}, {multiValued: true}),

	date: $.extend(date => {
		date = $u.date(date);

		return date? `${_.year(date)}-${_.month(date, "00")}-${_.day(date, "00")}` : "";
	}, {multiValued: true}),

	time: $.extend((date, precision = "seconds") => {
		date = $u.date(date);

		if (!date) {
			return "";
		}

		var ret = `${_.hour(date, "00")}:${precision == "hours"? "00" : _.minute(date, "00")}`;

		if (precision == "seconds" || precision == "ms") {
			ret += `:${_.second(date, "00")}`;

			if (precision == "ms") {
				ret += `.${_.ms(date)}`;
			}
		}

		return ret;
	}, {multiValued: true}),

	localTimezone: -(new Date()).getTimezoneOffset(),
});

_.msTo = (what, ms) => Math.floor(Math.abs(ms) / (s[what] * 1000)) || 0;

for (let unit in s) {
	_[unit] = $.extend(function(ms) {
		if (arguments.length === 0) {
			return s[unit] * 1000;
		}

		return _.msTo(unit, ms);
	}, {multiValued: true});
}

_.duration = $.extend(function(ms) {
	var count = ms || 0;
	var unit = "ms";

	for (let nextUnit in s) {
		var nextCount = _.msTo(nextUnit, ms);

		if (nextCount === 0) {
			break;
		}

		count = nextCount;
		unit = nextUnit;
	}

	unit = count === 1 && unit !== "ms"? unit.slice(0, -1) : unit;

	return count + " " + _.phrase.call(this, unit);
}, {
	needsContext: true
});

$.extend(_.util, {
	fixDateString: function(date) {
		date = date.trim();

		var hasDate = /^\d{4}-\d{2}(-\d{2})?/.test(date);
		var hasTime = date.indexOf(":") > -1;

		if (!hasDate && !hasTime) {
			return null;
		}

		// Fix up time format
		if (!hasDate) {
			// No date, add today’s
			date = _.$today + " " + date;
		}
		else {
			// Only year-month, add day
			date = date.replace(/^(\d{4}-\d{2})(?!-\d{2})/, "$1-01");
		}

		if (!hasTime) {
			// Add a time if one doesn't exist
			date += "T00:00:00";
		}
		else {
			// Make sure time starts with T, due to Safari bug
			date = date.replace(/\-(\d{2})\s+(?=\d{2}:)/, "-$1T");
		}

		// Remove all whitespace
		date = date.replace(/\s+/g, "");

		return date;
	},

	dateComponent: function(component, date, format) {
		if (arguments.length === 1 && component + "s" in s) {
			return _[component + "s"]();
		}

		var dateO = $u.date(date);

		if (component === "year") {
			// Why +""? We don't want years to be formatted like 2,017!
			// Why the .match()? For incomplete dates, see #226
			date = date && date.match? date : date + "";
			var ret = dateO? dateO.getFullYear() + "" : (date.match(/\b[1-9]\d\d\b|\d+/) || [])[0];
		}

		if (!ret && !dateO) {
			return "";
		}

		var ret = ret || numeric[component](dateO);

		if (format) {
			if (/^0+$/.test(format)) {
				// Leading zeroes
				return (ret + "").padStart(format.length, "0").slice(-format.length);
			}
			else {
				format = {name: "long", shortname: "short"}[format] || format;
				ret = dateO.toLocaleString(Mavo.locale, {[component]: format});
				ret = ret.replace(/\u200e/g, ""); // Stupid Edge bug

				return ret;
			}
		}

		return component === "year"? ret : +ret;
	},

	date: function(date) {
		date = val(date);

		if (!date) {
			return null;
		}

		var object = new Date(date);

		// Either arg is not string or is exactly the same as a re-serialization of it as a date
		if ($.type(date) !== "string" || !isNaN(object) && (object + "" == date)) {
			return object;
		}

		date = $u.fixDateString(date);

		if (date === null) {
			return null;
		}

		var timezone = date.match(/[+-]\d{2}:?\d{2}|Z$/)?.[0];

		if (timezone) {
			// parse as ISO format
			date = new Date(date);
		}
		else {
			// construct date in local timezone
			var fields = date.match(/\d+/g);

			date = new Date(
				// year, month, date,
				fields[0], (fields[1] || 1) - 1, fields[2] || 1,
				// hours, minutes, seconds, milliseconds,
				fields[3] || 0, fields[4] || 0, fields[5] || 0, fields[6] || 0
			);
		}

		return isNaN(date)? null : date;
	}
});

})(Bliss, Mavo.value, Mavo.Functions);
<commit_msg>Updated duration() to include terms parameter (#653)<commit_after>/**
 * Date Functions available inside Mavo expressions
 */

(function($, val, _, $u = _.util) {

var s = {seconds: 1, minutes: 60};
s.hours  = s.minutes * 60;
s.days   = s.hours   * 24;
s.weeks  = s.days    * 7;
s.months = s.days    * 30.4368;
s.years  = s.weeks  * 52;

var numeric = {
	year: d => d.getFullYear(),
	month: d => d.getMonth() + 1,
	day: d => d.getDate(),
	weekday: d => d.getDay() || 7,
	hour: d => d.getHours(),
	minute: d => d.getMinutes(),
	second: d => d.getSeconds(),
	ms: d => d.getMilliseconds()
};

$.extend(_, {
	get $now() {
		return new Date();
	},

	$startup: new Date(), // Like $now, but doesn't update

	get $today() {
		return _.date(new Date());
	},

	year: $.extend(function() {
		return $u.dateComponent("year", ...arguments);
	}, {multiValued: true}),

	month: $.extend(function() {
		return $u.dateComponent("month", ...arguments);
	}, {multiValued: true}),

	week: () => s.weeks * 1000,

	day: $.extend(function() {
		return $u.dateComponent("day", ...arguments);
	}, {multiValued: true}),

	weekday: $.extend(function() {
		return $u.dateComponent("weekday", ...arguments);
	}, {multiValued: true}),

	hour: $.extend(function() {
		return $u.dateComponent("hour", ...arguments);
	}, {multiValued: true}),

	minute: $.extend(function() {
		return $u.dateComponent("minute", ...arguments);
	}, {multiValued: true}),

	second: $.extend(function() {
		return $u.dateComponent("second", ...arguments);
	}, {multiValued: true}),

	ms: $.extend(function() {
		return $u.dateComponent("ms", ...arguments);
	}, {multiValued: true}),

	date: $.extend(date => {
		date = $u.date(date);

		return date? `${_.year(date)}-${_.month(date, "00")}-${_.day(date, "00")}` : "";
	}, {multiValued: true}),

	time: $.extend((date, precision = "seconds") => {
		date = $u.date(date);

		if (!date) {
			return "";
		}

		var ret = `${_.hour(date, "00")}:${precision == "hours"? "00" : _.minute(date, "00")}`;

		if (precision == "seconds" || precision == "ms") {
			ret += `:${_.second(date, "00")}`;

			if (precision == "ms") {
				ret += `.${_.ms(date)}`;
			}
		}

		return ret;
	}, {multiValued: true}),

	localTimezone: -(new Date()).getTimezoneOffset(),
});

_.msTo = (what, ms) => Math.floor(Math.abs(ms) / (s[what] * 1000)) || 0;

for (let unit in s) {
	_[unit] = $.extend(function(ms) {
		if (arguments.length === 0) {
			return s[unit] * 1000;
		}

		return _.msTo(unit, ms);
	}, {multiValued: true});
}

_.duration = $.extend(function (ms, terms) {
	if (ms === 0 || terms === undefined) {
		terms = 1;
	}

	let timeLeft = ms || 0;
	let ret = [];
	let units = Object.keys(s).reverse();
	units.push("ms");
	let noUnitSkipped = true;

	units.forEach(function(unit, index) {
		// get largest value of time unit for the remaining
		// time to account for
		let unitValue = unit === "ms"? timeLeft : _.msTo(unit, timeLeft);
		timeLeft -= unitValue * (unit === "ms" ? 1 : Mavo.Functions[unit]());

		if (unitValue !== 0 && ret.length < terms && noUnitSkipped) {
			let unitProperPlurality = unitValue === 1 && units[index] !== "ms" ? units[index].slice(0, -1) : units[index];
			ret.push(unitValue + " " + Mavo.Functions.phrase(this, unitProperPlurality));
		}
		else if (ret.length > 0) {
			// terms are no longer consecutive terms
			noUnitSkipped = false;
		}
	});

	if (ret.length === 0) {
		ret.push("0 ms");
	}

	return arguments.length === 1 ? ret[0] : ret;
}, {
	needsContext: true
});

$.extend(_.util, {
	fixDateString: function(date) {
		date = date.trim();

		var hasDate = /^\d{4}-\d{2}(-\d{2})?/.test(date);
		var hasTime = date.indexOf(":") > -1;

		if (!hasDate && !hasTime) {
			return null;
		}

		// Fix up time format
		if (!hasDate) {
			// No date, add today’s
			date = _.$today + " " + date;
		}
		else {
			// Only year-month, add day
			date = date.replace(/^(\d{4}-\d{2})(?!-\d{2})/, "$1-01");
		}

		if (!hasTime) {
			// Add a time if one doesn't exist
			date += "T00:00:00";
		}
		else {
			// Make sure time starts with T, due to Safari bug
			date = date.replace(/\-(\d{2})\s+(?=\d{2}:)/, "-$1T");
		}

		// Remove all whitespace
		date = date.replace(/\s+/g, "");

		return date;
	},

	dateComponent: function(component, date, format) {
		if (arguments.length === 1 && component + "s" in s) {
			return _[component + "s"]();
		}

		var dateO = $u.date(date);

		if (component === "year") {
			// Why +""? We don't want years to be formatted like 2,017!
			// Why the .match()? For incomplete dates, see #226
			date = date && date.match? date : date + "";
			var ret = dateO? dateO.getFullYear() + "" : (date.match(/\b[1-9]\d\d\b|\d+/) || [])[0];
		}

		if (!ret && !dateO) {
			return "";
		}

		var ret = ret || numeric[component](dateO);

		if (format) {
			if (/^0+$/.test(format)) {
				// Leading zeroes
				return (ret + "").padStart(format.length, "0").slice(-format.length);
			}
			else {
				format = {name: "long", shortname: "short"}[format] || format;
				ret = dateO.toLocaleString(Mavo.locale, {[component]: format});
				ret = ret.replace(/\u200e/g, ""); // Stupid Edge bug

				return ret;
			}
		}

		return component === "year"? ret : +ret;
	},

	date: function(date) {
		date = val(date);

		if (!date) {
			return null;
		}

		var object = new Date(date);

		// Either arg is not string or is exactly the same as a re-serialization of it as a date
		if ($.type(date) !== "string" || !isNaN(object) && (object + "" == date)) {
			return object;
		}

		date = $u.fixDateString(date);

		if (date === null) {
			return null;
		}

		var timezone = date.match(/[+-]\d{2}:?\d{2}|Z$/)?.[0];

		if (timezone) {
			// parse as ISO format
			date = new Date(date);
		}
		else {
			// construct date in local timezone
			var fields = date.match(/\d+/g);

			date = new Date(
				// year, month, date,
				fields[0], (fields[1] || 1) - 1, fields[2] || 1,
				// hours, minutes, seconds, milliseconds,
				fields[3] || 0, fields[4] || 0, fields[5] || 0, fields[6] || 0
			);
		}

		return isNaN(date)? null : date;
	}
});

})(Bliss, Mavo.value, Mavo.Functions);
<|endoftext|>


<commit_before>/*
Name:         openkvk
Description:  node.is module to access the OpenKvK.nl webservice.
Author:       Franklin van de Meent (https://frankl.in)
Source code:  https://github.com/fvdm/nodejs-openkvk
Feedback:     https://github.com/fvdm/nodejs-openkvk/issues
License:      Unlicense (Public Domain) - see LICENSE file
              (https://github.com/fvdm/nodejs-openkvk/raw/master/LICENSE)
*/

var http = require ('http');

module.exports = function (term, callback) {
  // prevent multiple callbacks
  var complete = false;
  function doCallback (err, res) {
    if (!complete) {
      complete = true;
      callback (err, res);
    }
  }

  // build request
  var options = {
    host: 'officieel.openkvk.nl',
    path: '/json/'+ encodeURIComponent (term),
    header: {
      'User-Agent': 'openkvk.js (https://www.npmjs.com/package/openkvk'
    }
  };

  var request = http.request (options);

  request.on ('response', function (response) {
    var data = [];
    var size = 0;

    response.on ('data', function (ch) {
      data.push (ch);
      size += ch.length;
    });

    response.on ('close', function () {
      doCallback (new Error ('request dropped') );
    });

    response.on ('end', function() {
      data = new Buffer.concat (data, size) .toString ('utf8') .trim ();
      try {
        data = JSON.parse (data);
        doCallback (null, data);
      }
      catch(e) {
        doCallback (new Error ('not json') );
      }
    });
  });

  // request error
  request.on ('error', function (error) {
    var err = new Error ('request failed');
    err.error = error;
    doCallback (error);
  });

  // do it
  request.end ();
};
<commit_msg>Refactor(main): Rewrite all code<commit_after>/*
Name:         openkvk
Description:  node.is module to access the OpenKvK.nl webservice.
Author:       Franklin van de Meent (https://frankl.in)
Source code:  https://github.com/fvdm/nodejs-openkvk
Feedback:     https://github.com/fvdm/nodejs-openkvk/issues
License:      Unlicense (Public Domain) - see LICENSE file
              (https://github.com/fvdm/nodejs-openkvk/raw/master/LICENSE)
*/

var httpreq = require ('httpreq');

/**
 * Process httpreq response
 *
 * @callback callback
 * @param err {Error, null} - Client error
 * @param res {object} - Client response details
 * @param callback {function) - `function (err, data) {}`
 * @returns {void}
 */

function httpResponse (err, res, callback) {
  var data = res && res.body || null;
  var error = null;

  if (err) {
    callback (err);
    return;
  }

  try {
    data = JSON.parse (data);
  } catch (e) {
    error = new Error ('not json');
    error.error = e;
    error.body = data;
    error.statusCode = res.statusCode;

    callback (error);
    return;
  }

  callback (null, data);
}

/**
 * Send API request
 *
 * @callback callback
 * @param term {string} - Term to lookup
 * @param callback {function) - `function (err, data) {}`
 * @returns apiRequest {function}
 */

function apiRequest (term, callback) {
  var options = {
    method: 'GET',
    url: 'http://officieel.openkvk.nl/json/' + encodeURIComponent (term),
    header: {
      'User-Agent': 'openkvk.js (https://www.npmjs.com/package/openkvk'
    }
  };

  httpreq.doRequest (options, function (err, res) {
    httpResponse (err, res, callback);
  });

  return apiRequest;
}

module.exports = apiRequest;
<|endoftext|>