<commit_before>'use strict';
var CompositeDisposable = require('atom').CompositeDisposable;
var emissary = require('emissary');
var lazyReq = require('lazy-req')(require);
var lodash = lazyReq('lodash');
var jshint = lazyReq('jshint');
var jsxhint = lazyReq('jshint-jsx');
var path = require('path');
var cli = lazyReq('jshint/src/cli');
var reactDomPragma = require('react-dom-pragma');
var loadConfig = lazyReq('./load-config');
var plugin = module.exports;
var _;
var markersByEditorId = {};
var errorsByEditorId = {};
var subscriptionTooltips = new CompositeDisposable();

emissary.Subscriber.extend(plugin);

var SUPPORTED_GRAMMARS = [
	'source.js',
	'source.jsx',
	'source.js.jsx'
];

function getMarkersForEditor() {
	var editor = atom.workspace.getActiveTextEditor();

	if (editor && markersByEditorId[editor.id]) {
		return markersByEditorId[editor.id];
	}

	return {};
}

function getErrorsForEditor() {
	var editor = atom.workspace.getActiveTextEditor();

	if (editor && errorsByEditorId[editor.id]) {
		return errorsByEditorId[editor.id];
	}

	return [];
}

function clearOldMarkers(errors) {
	subscriptionTooltips.dispose();

	var rows = _.map(errors, function (error) {
		return getRowForError(error);
	});

	var oldMarkers = getMarkersForEditor();
	_.each(_.keys(oldMarkers), function (row) {
		if (!_.contains(rows, row)) {
			destroyMarkerAtRow(row);
		}
	});
}

function destroyMarkerAtRow(row) {
	var editor = atom.workspace.getActiveTextEditor();
	if (markersByEditorId[editor.id] && markersByEditorId[editor.id][row]) {
		markersByEditorId[editor.id][row].destroy();
		delete markersByEditorId[editor.id][row];
	}
}

function saveMarker(marker, row) {
	var editor = atom.workspace.getActiveTextEditor();

	if (!markersByEditorId[editor.id]) {
		markersByEditorId[editor.id] = {};
	}

	markersByEditorId[editor.id][row] = marker;
}

function getMarkerAtRow(row) {
	var editor = atom.workspace.getActiveTextEditor();

	if (!markersByEditorId[editor.id]) {
		return null;
	}

	return markersByEditorId[editor.id][row];
}

function updateStatusbar() {
	var statusBar = atom.views.getView(atom.workspace).querySelector('.status-bar');
	if (!statusBar) {
		return;
	}

	var jsHintStatusBar = statusBar.querySelector('#jshint-statusbar');
	if (jsHintStatusBar && jsHintStatusBar.parentNode) {
		jsHintStatusBar.parentNode.removeChild(jsHintStatusBar);
	}

	var editor = atom.workspace.getActiveTextEditor();
	if (!editor || !errorsByEditorId[editor.id]) {
		return;
	}

	var line = editor.getCursorBufferPosition().row+1;
	var error = errorsByEditorId[editor.id][line] || _.first(_.compact(errorsByEditorId[editor.id]));
	error = error[0];

	statusBar.appendLeft('JSHint ' + error.line + ':' + error.character + ' ' + error.reason + '');
}

function getRowForError(error) {
	var line = error[0].line || 1; // JSHint reports `line: 0` when config error
	var row = line - 1;
	return row;
}

function displayError(error) {
	var row = getRowForError(error);

	if (getMarkerAtRow(row)) {
		return;
	}

	var editor = atom.workspace.getActiveTextEditor();
	var marker = editor.markBufferRange([[row, 0], [row, 1]]);
	editor.decorateMarker(marker, {type: 'line', class: 'jshint-line'});
	editor.decorateMarker(marker, {type: 'gutter', class: 'jshint-line-number'});
	saveMarker(marker, row);
	addReasons(marker, error);
}

function getReasonsForError(error) {
	return _.map(error, function (el) {
		return el.character + ': ' + el.reason;
	});
}

function addReasons(marker, error) {
	var row = getRowForError(error);
	var editorElement = atom.views.getView(atom.workspace.getActiveTextEditor());
	var reasons = '
' + getReasonsForError(error).join('
') + '
';

	var target = editorElement.shadowRoot.querySelectorAll('.jshint-line-number.line-number-' + row);
	var tooltip = atom.tooltips.add(target, {
		title: reasons,
		placement: 'bottom',
		delay: { show: 200 }
	});
	subscriptionTooltips.add(tooltip);
}

function lint() {
	var editor = atom.workspace.getActiveTextEditor();

	if (!editor) {
		return;
	}

	if (SUPPORTED_GRAMMARS.indexOf(editor.getGrammar().scopeName) === -1) {
		return;
	}

	var file = editor.getUri();

	// Hack to make JSHint look for .jshintignore in the correct dir
	// Because JSHint doesn't use its `cwd` option
	process.chdir(path.dirname(file));

	// Remove errors and don't lint if file is ignored in .jshintignore
	if (file && cli().gather({args: [file]}).length === 0) {
		removeErrorsForEditorId(editor.id);
		displayErrors();
		removeMarkersForEditorId(editor.id);
		return;
	}

	var config = file ? loadConfig()(file) : {};

	var linter = (atom.config.get('jshint.supportLintingJsx') || atom.config.get('jshint.transformJsx')) ? jsxhint().JSXHINT : jshint().JSHINT;

	var origCode = editor.getText();
	var code = editor.getGrammar().scopeName === 'source.jsx' ? reactDomPragma(origCode) : origCode;
	var pragmaWasAdded = code !== origCode;

	try {
		linter(code, config, config.globals);
	} catch (err) {}

	removeErrorsForEditorId(editor.id);

	// workaround the errors array sometimes containing `null`
	var errors = _.compact(linter.errors);

	if (errors.length > 0) {
		// aggregate same-line errors
		var ret = [];
		_.each(errors, function (el) {
			if (pragmaWasAdded) {
				el.line--;
			}

			var l = el.line;

			if (Array.isArray(ret[l])) {
				ret[l].push(el);

				ret[l] = _.sortBy(ret[l], function (el) {
					return el.character;
				});
			} else {
				ret[l] = [el];
			}
		});

		errorsByEditorId[editor.id] = ret;
	}

	displayErrors();
}

function displayErrors() {
	var errors = _.compact(getErrorsForEditor());
	clearOldMarkers(errors);
	updateStatusbar();
	_.each(errors, displayError);
}

function removeMarkersForEditorId(id) {
	if (markersByEditorId[id]) {
		delete markersByEditorId[id];
	}
}

function removeErrorsForEditorId(id) {
	if (errorsByEditorId[id]) {
		delete errorsByEditorId[id];
	}
}

function registerEvents() {
	lint();
	var workspaceElement = atom.views.getView(atom.workspace);

	atom.workspace.observeTextEditors(function (editor) {
		var buffer = editor.getBuffer();
		var events = 'saved contents-modified';

		editor.off('scroll-top-changed');
		plugin.unsubscribe(buffer);

		if (atom.config.get('jshint.validateOnlyOnSave')) {
			events = 'saved';
		}

		editor.onDidChangeScrollTop(_.debounce(displayErrors, 200));

		plugin.subscribe(buffer, events, _.debounce(lint, 50));
	});

	workspaceElement.addEventListener('editor:will-be-removed', function (e, editorView) {
		if (editorView && editorView.editor) {
			removeErrorsForEditorId(editorView.editor.id);
			removeMarkersForEditorId(editorView.editor.id);
		}
	});

	workspaceElement.addEventListener('cursor:moved', updateStatusbar);
}

plugin.config = {
	validateOnlyOnSave: {
		type: 'boolean',
		default: false
	},
	supportLintingJsx: {
		type: 'boolean',
		default: false,
		title: 'Support Linting JSX'
	}
};

plugin.activate = function () {
	_ = lodash();
	registerEvents();
	plugin.subscribe(atom.config.observe('jshint.validateOnlyOnSave', registerEvents));
	atom.commands.add('atom-workspace', 'jshint:lint', lint);
};
<commit_msg>fix some deprecations<commit_after>'use strict';
var CompositeDisposable = require('atom').CompositeDisposable;
var emissary = require('emissary');
var lazyReq = require('lazy-req')(require);
var lodash = lazyReq('lodash');
var jshint = lazyReq('jshint');
var jsxhint = lazyReq('jshint-jsx');
var path = require('path');
var cli = lazyReq('jshint/src/cli');
var reactDomPragma = require('react-dom-pragma');
var loadConfig = lazyReq('./load-config');
var plugin = module.exports;
var _;
var markersByEditorId = {};
var errorsByEditorId = {};
var subscriptionTooltips = new CompositeDisposable();

emissary.Subscriber.extend(plugin);

var SUPPORTED_GRAMMARS = [
	'source.js',
	'source.jsx',
	'source.js.jsx'
];

function getMarkersForEditor() {
	var editor = atom.workspace.getActiveTextEditor();

	if (editor && markersByEditorId[editor.id]) {
		return markersByEditorId[editor.id];
	}

	return {};
}

function getErrorsForEditor() {
	var editor = atom.workspace.getActiveTextEditor();

	if (editor && errorsByEditorId[editor.id]) {
		return errorsByEditorId[editor.id];
	}

	return [];
}

function clearOldMarkers(errors) {
	subscriptionTooltips.dispose();

	var rows = _.map(errors, function (error) {
		return getRowForError(error);
	});

	var oldMarkers = getMarkersForEditor();
	_.each(_.keys(oldMarkers), function (row) {
		if (!_.contains(rows, row)) {
			destroyMarkerAtRow(row);
		}
	});
}

function destroyMarkerAtRow(row) {
	var editor = atom.workspace.getActiveTextEditor();
	if (markersByEditorId[editor.id] && markersByEditorId[editor.id][row]) {
		markersByEditorId[editor.id][row].destroy();
		delete markersByEditorId[editor.id][row];
	}
}

function saveMarker(marker, row) {
	var editor = atom.workspace.getActiveTextEditor();

	if (!markersByEditorId[editor.id]) {
		markersByEditorId[editor.id] = {};
	}

	markersByEditorId[editor.id][row] = marker;
}

function getMarkerAtRow(row) {
	var editor = atom.workspace.getActiveTextEditor();

	if (!markersByEditorId[editor.id]) {
		return null;
	}

	return markersByEditorId[editor.id][row];
}

function updateStatusbar() {
	var statusBar = atom.views.getView(atom.workspace).querySelector('.status-bar');
	if (!statusBar) {
		return;
	}

	var jsHintStatusBar = statusBar.querySelector('#jshint-statusbar');
	if (jsHintStatusBar && jsHintStatusBar.parentNode) {
		jsHintStatusBar.parentNode.removeChild(jsHintStatusBar);
	}

	var editor = atom.workspace.getActiveTextEditor();
	if (!editor || !errorsByEditorId[editor.id]) {
		return;
	}

	var line = editor.getCursorBufferPosition().row+1;
	var error = errorsByEditorId[editor.id][line] || _.first(_.compact(errorsByEditorId[editor.id]));
	error = error[0];

	statusBar.appendLeft('JSHint ' + error.line + ':' + error.character + ' ' + error.reason + '');
}

function getRowForError(error) {
	var line = error[0].line || 1; // JSHint reports `line: 0` when config error
	var row = line - 1;
	return row;
}

function displayError(error) {
	var row = getRowForError(error);

	if (getMarkerAtRow(row)) {
		return;
	}

	var editor = atom.workspace.getActiveTextEditor();
	var marker = editor.markBufferRange([[row, 0], [row, 1]]);
	editor.decorateMarker(marker, {type: 'line', class: 'jshint-line'});
	editor.decorateMarker(marker, {type: 'line-number', class: 'jshint-line-number'});
	saveMarker(marker, row);
	addReasons(marker, error);
}

function getReasonsForError(error) {
	return _.map(error, function (el) {
		return el.character + ': ' + el.reason;
	});
}

function addReasons(marker, error) {
	var row = getRowForError(error);
	var editorElement = atom.views.getView(atom.workspace.getActiveTextEditor());
	var reasons = '
' + getReasonsForError(error).join('
') + '
';

	var target = editorElement.shadowRoot.querySelectorAll('.jshint-line-number.line-number-' + row);
	var tooltip = atom.tooltips.add(target, {
		title: reasons,
		placement: 'bottom',
		delay: { show: 200 }
	});
	subscriptionTooltips.add(tooltip);
}

function lint() {
	var editor = atom.workspace.getActiveTextEditor();

	if (!editor) {
		return;
	}

	if (SUPPORTED_GRAMMARS.indexOf(editor.getGrammar().scopeName) === -1) {
		return;
	}

	var file = editor.getURI();

	// Hack to make JSHint look for .jshintignore in the correct dir
	// Because JSHint doesn't use its `cwd` option
	process.chdir(path.dirname(file));

	// Remove errors and don't lint if file is ignored in .jshintignore
	if (file && cli().gather({args: [file]}).length === 0) {
		removeErrorsForEditorId(editor.id);
		displayErrors();
		removeMarkersForEditorId(editor.id);
		return;
	}

	var config = file ? loadConfig()(file) : {};

	var linter = (atom.config.get('jshint.supportLintingJsx') || atom.config.get('jshint.transformJsx')) ? jsxhint().JSXHINT : jshint().JSHINT;

	var origCode = editor.getText();
	var code = editor.getGrammar().scopeName === 'source.jsx' ? reactDomPragma(origCode) : origCode;
	var pragmaWasAdded = code !== origCode;

	try {
		linter(code, config, config.globals);
	} catch (err) {}

	removeErrorsForEditorId(editor.id);

	// workaround the errors array sometimes containing `null`
	var errors = _.compact(linter.errors);

	if (errors.length > 0) {
		// aggregate same-line errors
		var ret = [];
		_.each(errors, function (el) {
			if (pragmaWasAdded) {
				el.line--;
			}

			var l = el.line;

			if (Array.isArray(ret[l])) {
				ret[l].push(el);

				ret[l] = _.sortBy(ret[l], function (el) {
					return el.character;
				});
			} else {
				ret[l] = [el];
			}
		});

		errorsByEditorId[editor.id] = ret;
	}

	displayErrors();
}

function displayErrors() {
	var errors = _.compact(getErrorsForEditor());
	clearOldMarkers(errors);
	updateStatusbar();
	_.each(errors, displayError);
}

function removeMarkersForEditorId(id) {
	if (markersByEditorId[id]) {
		delete markersByEditorId[id];
	}
}

function removeErrorsForEditorId(id) {
	if (errorsByEditorId[id]) {
		delete errorsByEditorId[id];
	}
}

function registerEvents() {
	lint();
	var workspaceElement = atom.views.getView(atom.workspace);

	atom.workspace.observeTextEditors(function (editor) {
		var buffer = editor.getBuffer();
		var events = 'saved contents-modified';

		editor.off('scroll-top-changed');
		plugin.unsubscribe(buffer);

		if (atom.config.get('jshint.validateOnlyOnSave')) {
			events = 'saved';
		}

		editor.onDidChangeScrollTop(_.debounce(displayErrors, 200));

		plugin.subscribe(buffer, events, _.debounce(lint, 50));
	});

	workspaceElement.addEventListener('editor:will-be-removed', function (e, editorView) {
		if (editorView && editorView.editor) {
			removeErrorsForEditorId(editorView.editor.id);
			removeMarkersForEditorId(editorView.editor.id);
		}
	});

	workspaceElement.addEventListener('cursor:moved', updateStatusbar);
}

plugin.config = {
	validateOnlyOnSave: {
		type: 'boolean',
		default: false
	},
	supportLintingJsx: {
		type: 'boolean',
		default: false,
		title: 'Support Linting JSX'
	}
};

plugin.activate = function () {
	_ = lodash();
	registerEvents();
	plugin.subscribe(atom.config.observe('jshint.validateOnlyOnSave', registerEvents));
	atom.commands.add('atom-workspace', 'jshint:lint', lint);
};
<|endoftext|>


<commit_before>(function ()
{
  module("utils");

  var loadNotes_cases  = [
    {
      title: "Single note",
      notes: [
        { "time": 40, "text": "c", "tags": [] }
      ],
      expectedCalls:[
        [{"time":40,"text":"c","tags":[]},"_root",null]
      ]
    },
    {
      title: "Two notes",
      notes: [
        { "time": 40, "text": "a", "tags": [] },
        { "time": 40, "text": "b", "tags": [] }
      ],
      expectedCalls:[
        [{"time":40,"text":"a","tags":[]},"_root",null],
        [{"time":40,"text":"b","tags":[]},"_root",null]
      ]
    },
    {
      title: "Sub-Note - one lvl",
      notes: [
        {
          "time": 20, "text": "a", "tags": [],
          "notes": [ { "time": 30, "text": "b", "tags": [] } ]
        }
      ],
      expectedCalls:[
        [{"time":20,"text":"a","tags":[]},"_root",null],
        [{"time":30,"text":"b","tags":[]},"a",null]
      ]
    },
    {
      title: "Sub-Note - two lvls",
      notes: [
        {
          "time": 20, "text": "a", "tags": [],
          "notes":
            [
              {
                "time": 30, "text": "b", "tags": [],
                "notes": [ { "time": 40, "text": "c", "tags": [] } ]
              }
            ]
        }
      ],
      expectedCalls:[
        [{"time":20,"text":"a","tags":[]},"_root",null],
        [{"time":30,"text":"b","tags":[]},"a",null],
        [{"time":40,"text":"c","tags":[]},"b",null]
      ]
    },
  ];

  QUnit.cases(loadNotes_cases).asyncTest("loadNotes",
    function (params)
    {
      var currentCall = 0;
      var fakeConnector = {
        addNote : function ()
        {
          var args = Array.prototype.slice.call(arguments);
          var cb = args[args.length - 1];
          args[0] = osftools.cloneNote(args[0], false);
          var note = args[0];
          args[args.length - 1] = null;

          deepEqual(args, params.expectedCalls[currentCall]);
          currentCall++;

          cb(null, note.text); // call callback
        }
      };

      shownoteseditor.utils.loadNotes(fakeConnector, params.notes,
        function ()
        {
          start();
        }
      );
    }
  );
})();
<commit_msg>fixed utils tests<commit_after>(function ()
{
  module("utils");

  var loadNotes_cases  = [
    {
      title: "Single note",
      notes: [
        { "time": 40, "text": "c", "link": "", "tags": [] }
      ],
      expectedCalls:[
        [{"time":40,"text":"c","link":"","tags":[]},"_root",null]
      ]
    },
    {
      title: "Two notes",
      notes: [
        { "time": 40, "text": "a", "link": "", "tags": [] },
        { "time": 40, "text": "b", "link": "", "tags": [] }
      ],
      expectedCalls:[
        [{"time":40,"text":"a","link":"","tags":[]},"_root",null],
        [{"time":40,"text":"b","link":"","tags":[]},"_root",null]
      ]
    },
    {
      title: "Sub-Note - one lvl",
      notes: [
        {
          "time": 20, "text": "a", "link": "", "tags": [],
          "notes": [ { "time": 30, "text": "b", "link": "", "tags": [] } ]
        }
      ],
      expectedCalls:[
        [{"time":20,"text":"a","link":"","tags":[]},"_root",null],
        [{"time":30,"text":"b","link":"","tags":[]},"a",null]
      ]
    },
    {
      title: "Sub-Note - two lvls",
      notes: [
        {
          "time": 20, "text": "a", "tags": [],
          "notes":
            [
              {
                "time": 30, "text": "b", "tags": [],
                "notes": [ { "time": 40, "text": "c", "tags": [] } ]
              }
            ]
        }
      ],
      expectedCalls:[
        [{"time":20,"text":"a","link":"","tags":[]},"_root",null],
        [{"time":30,"text":"b","link":"","tags":[]},"a",null],
        [{"time":40,"text":"c","link":"","tags":[]},"b",null]
      ]
    },
  ];

  QUnit.cases(loadNotes_cases).asyncTest("loadNotes",
    function (params)
    {
      var currentCall = 0;
      var fakeConnector = {
        addNote : function ()
        {
          var args = Array.prototype.slice.call(arguments);
          var cb = args[args.length - 1];
          args[0] = osftools.cloneNote(args[0], false);
          var note = args[0];
          args[args.length - 1] = null;

          deepEqual(args, params.expectedCalls[currentCall]);
          currentCall++;

          cb(null, note.text); // call callback
        }
      };

      shownoteseditor.utils.loadNotes(fakeConnector, params.notes,
        function ()
        {
          start();
        }
      );
    }
  );
})();
<|endoftext|>


<commit_before>import React, { Component, PureComponent, forwardRef } from "react"
import hoistStatics from "hoist-non-react-statics"
import { createAtom, Reaction, _allowStateChanges, $mobx } from "mobx"
import { findDOMNode as baseFindDOMNode } from "react-dom"

import EventEmitter from "./utils/EventEmitter"
import inject from "./inject"
import { patch as newPatch, newSymbol } from "./utils/utils"

const mobxAdminProperty = $mobx || "$mobx"
const mobxIsUnmounted = newSymbol("isUnmounted")

/**
 * dev tool support
 */
let isDevtoolsEnabled = false

let isUsingStaticRendering = false

let warnedAboutObserverInjectDeprecation = false

// WeakMap<Node, Object>;
export const componentByNodeRegistry = typeof WeakMap !== "undefined" ? new WeakMap() : undefined
export const renderReporter = new EventEmitter()

const skipRenderKey = newSymbol("skipRender")
const isForcingUpdateKey = newSymbol("isForcingUpdate")

// Using react-is had some issues (and operates on elements, not on types), see #608 / #609
const ReactForwardRefSymbol =
    typeof forwardRef === "function" && forwardRef((_props, _ref) => {})["$$typeof"]

/**
 * Helper to set `prop` to `this` as non-enumerable (hidden prop)
 * @param target
 * @param prop
 * @param value
 */
function setHiddenProp(target, prop, value) {
    if (!Object.hasOwnProperty.call(target, prop)) {
        Object.defineProperty(target, prop, {
            enumerable: false,
            configurable: true,
            writable: true,
            value
        })
    } else {
        target[prop] = value
    }
}

function findDOMNode(component) {
    if (baseFindDOMNode) {
        try {
            return baseFindDOMNode(component)
        } catch (e) {
            // findDOMNode will throw in react-test-renderer, see:
            // See https://github.com/mobxjs/mobx-react/issues/216
            // Is there a better heuristic?
            return null
        }
    }
    return null
}

function reportRendering(component) {
    const node = findDOMNode(component)
    if (node && componentByNodeRegistry) componentByNodeRegistry.set(node, component)

    renderReporter.emit({
        event: "render",
        renderTime: component.__$mobRenderEnd - component.__$mobRenderStart,
        totalTime: Date.now() - component.__$mobRenderStart,
        component: component,
        node: node
    })
}

export function trackComponents() {
    if (typeof WeakMap === "undefined")
        throw new Error("[mobx-react] tracking components is not supported in this browser.")
    if (!isDevtoolsEnabled) isDevtoolsEnabled = true
}

export function useStaticRendering(useStaticRendering) {
    isUsingStaticRendering = useStaticRendering
}

/**
 * Errors reporter
 */

export const errorsReporter = new EventEmitter()

/**
 * Utilities
 */

function patch(target, funcName) {
    newPatch(target, funcName, reactiveMixin[funcName])
}

function shallowEqual(objA, objB) {
    //From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
    if (is(objA, objB)) return true
    if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
        return false
    }
    const keysA = Object.keys(objA)
    const keysB = Object.keys(objB)
    if (keysA.length !== keysB.length) return false
    for (let i = 0; i < keysA.length; i++) {
        if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
            return false
        }
    }
    return true
}

function is(x, y) {
    // From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
    if (x === y) {
        return x !== 0 || 1 / x === 1 / y
    } else {
        return x !== x && y !== y
    }
}

function makeComponentReactive(render) {
    if (isUsingStaticRendering === true) return render.call(this)

    function reactiveRender() {
        isRenderingPending = false
        let exception = undefined
        let rendering = undefined
        reaction.track(() => {
            if (isDevtoolsEnabled) {
                this.__$mobRenderStart = Date.now()
            }
            try {
                rendering = _allowStateChanges(false, baseRender)
            } catch (e) {
                exception = e
            }
            if (isDevtoolsEnabled) {
                this.__$mobRenderEnd = Date.now()
            }
        })
        if (exception) {
            errorsReporter.emit(exception)
            throw exception
        }
        return rendering
    }

    // Generate friendly name for debugging
    const initialName =
        this.displayName ||
        this.name ||
        (this.constructor && (this.constructor.displayName || this.constructor.name)) ||
        "<component>"
    const rootNodeID =
        (this._reactInternalInstance && this._reactInternalInstance._rootNodeID) ||
        (this._reactInternalInstance && this._reactInternalInstance._debugID) ||
        (this._reactInternalFiber && this._reactInternalFiber._debugID)
    /**
     * If props are shallowly modified, react will render anyway,
     * so atom.reportChanged() should not result in yet another re-render
     */
    setHiddenProp(this, skipRenderKey, false)
    /**
     * forceUpdate will re-assign this.props. We don't want that to cause a loop,
     * so detect these changes
     */
    setHiddenProp(this, isForcingUpdateKey, false)

    // wire up reactive render
    const baseRender = render.bind(this)
    let isRenderingPending = false

    const reaction = new Reaction(`${initialName}#${rootNodeID}.render()`, () => {
        if (!isRenderingPending) {
            // N.B. Getting here *before mounting* means that a component constructor has side effects (see the relevant test in misc.js)
            // This unidiomatic React usage but React will correctly warn about this so we continue as usual
            // See #85 / Pull #44
            isRenderingPending = true
            if (typeof this.componentWillReact === "function") this.componentWillReact() // TODO: wrap in action?
            if (this[mobxIsUnmounted] !== true) {
                // If we are unmounted at this point, componentWillReact() had a side effect causing the component to unmounted
                // TODO: remove this check? Then react will properly warn about the fact that this should not happen? See #73
                // However, people also claim this might happen during unit tests..
                let hasError = true
                try {
                    setHiddenProp(this, isForcingUpdateKey, true)
                    if (!this[skipRenderKey]) Component.prototype.forceUpdate.call(this)
                    hasError = false
                } finally {
                    setHiddenProp(this, isForcingUpdateKey, false)
                    if (hasError) reaction.dispose()
                }
            }
        }
    })
    reaction.reactComponent = this
    reactiveRender[mobxAdminProperty] = reaction
    this.render = reactiveRender
    return reactiveRender.call(this)
}

/**
 * ReactiveMixin
 */
const reactiveMixin = {
    componentWillUnmount: function() {
        if (isUsingStaticRendering === true) return
        this.render[mobxAdminProperty] && this.render[mobxAdminProperty].dispose()
        this[mobxIsUnmounted] = true
        if (isDevtoolsEnabled) {
            const node = findDOMNode(this)
            if (node && componentByNodeRegistry) {
                componentByNodeRegistry.delete(node)
            }
            renderReporter.emit({
                event: "destroy",
                component: this,
                node: node
            })
        }
    },

    componentDidMount: function() {
        if (isDevtoolsEnabled) {
            reportRendering(this)
        }
    },

    componentDidUpdate: function() {
        if (isDevtoolsEnabled) {
            reportRendering(this)
        }
    },

    shouldComponentUpdate: function(nextProps, nextState) {
        if (isUsingStaticRendering) {
            console.warn(
                "[mobx-react] It seems that a re-rendering of a React component is triggered while in static (server-side) mode. Please make sure components are rendered only once server-side."
            )
        }
        // update on any state changes (as is the default)
        if (this.state !== nextState) {
            return true
        }
        // update if props are shallowly not equal, inspired by PureRenderMixin
        // we could return just 'false' here, and avoid the `skipRender` checks etc
        // however, it is nicer if lifecycle events are triggered like usually,
        // so we return true here if props are shallowly modified.
        return !shallowEqual(this.props, nextProps)
    }
}

function makeObservableProp(target, propName) {
    const valueHolderKey = newSymbol(`reactProp_${propName}_valueHolder`)
    const atomHolderKey = newSymbol(`reactProp_${propName}_atomHolder`)
    function getAtom() {
        if (!this[atomHolderKey]) {
            setHiddenProp(this, atomHolderKey, createAtom("reactive " + propName))
        }
        return this[atomHolderKey]
    }
    Object.defineProperty(target, propName, {
        configurable: true,
        enumerable: true,
        get: function() {
            getAtom.call(this).reportObserved()
            return this[valueHolderKey]
        },
        set: function set(v) {
            if (!this[isForcingUpdateKey] && !shallowEqual(this[valueHolderKey], v)) {
                setHiddenProp(this, valueHolderKey, v)
                setHiddenProp(this, skipRenderKey, true)
                getAtom.call(this).reportChanged()
                setHiddenProp(this, skipRenderKey, false)
            } else {
                setHiddenProp(this, valueHolderKey, v)
            }
        }
    })
}

/**
 * Observer function / decorator
 */
export function observer(arg1, arg2) {
    if (typeof arg1 === "string") {
        throw new Error("Store names should be provided as array")
    }
    if (Array.isArray(arg1)) {
        // TODO: remove in next major
        // component needs stores
        if (!warnedAboutObserverInjectDeprecation) {
            warnedAboutObserverInjectDeprecation = true
            console.warn(
                'Mobx observer: Using observer to inject stores is deprecated since 4.0. Use `@inject("store1", "store2") @observer ComponentClass` or `inject("store1", "store2")(observer(componentClass))` instead of `@observer(["store1", "store2"]) ComponentClass`'
            )
        }
        if (!arg2) {
            // invoked as decorator
            return componentClass => observer(arg1, componentClass)
        } else {
            return inject.apply(null, arg1)(observer(arg2))
        }
    }
    const componentClass = arg1

    if (componentClass.isMobxInjector === true) {
        console.warn(
            "Mobx observer: You are trying to use 'observer' on a component that already has 'inject'. Please apply 'observer' before applying 'inject'"
        )
    }
    if (componentClass.__proto__ === PureComponent) {
        console.warn(
            "Mobx observer: You are using 'observer' on React.PureComponent. These two achieve two opposite goals and should not be used together"
        )
    }

    // Unwrap forward refs into `<Observer>` component
    // we need to unwrap the render, because it is the inner render that needs to be tracked,
    // not the ForwardRef HoC
    if (ReactForwardRefSymbol && componentClass["$$typeof"] === ReactForwardRefSymbol) {
        const baseRender = componentClass.render
        if (typeof baseRender !== "function")
            throw new Error("render property of ForwardRef was not a function")
        return forwardRef(function ObserverForwardRef() {
            return <Observer>{() => baseRender.apply(undefined, arguments)}</Observer>
        })
    }

    // Stateless function component:
    // If it is function but doesn't seem to be a react class constructor,
    // wrap it to a react class automatically
    if (
        typeof componentClass === "function" &&
        (!componentClass.prototype || !componentClass.prototype.render) &&
        !componentClass.isReactClass &&
        !Component.isPrototypeOf(componentClass)
    ) {
        const observerComponent = observer(
            class extends Component {
                static displayName = componentClass.displayName || componentClass.name
                static contextTypes = componentClass.contextTypes
                static propTypes = componentClass.propTypes
                static defaultProps = componentClass.defaultProps
                render() {
                    return componentClass.call(this, this.props, this.context)
                }
            }
        )
        hoistStatics(observerComponent, componentClass)
        return observerComponent
    }

    if (!componentClass) {
        throw new Error("Please pass a valid component to 'observer'")
    }

    const target = componentClass.prototype || componentClass
    mixinLifecycleEvents(target)
    componentClass.isMobXReactObserver = true
    makeObservableProp(target, "props")
    makeObservableProp(target, "state")
    const baseRender = target.render
    target.render = function() {
        return makeComponentReactive.call(this, baseRender)
    }
    return componentClass
}

function mixinLifecycleEvents(target) {
    ;["componentDidMount", "componentWillUnmount", "componentDidUpdate"].forEach(function(
        funcName
    ) {
        patch(target, funcName)
    })
    if (!target.shouldComponentUpdate) {
        target.shouldComponentUpdate = reactiveMixin.shouldComponentUpdate
    } else {
        if (target.shouldComponentUpdate !== reactiveMixin.shouldComponentUpdate) {
            // TODO: make throw in next major
            console.warn(
                "Use `shouldComponentUpdate` in an `observer` based component breaks the behavior of `observer` and might lead to unexpected results. Manually implementing `sCU` should not be needed when using mobx-react."
            )
        }
    }
}

export const Observer = observer(({ children, inject: observerInject, render }) => {
    const component = children || render
    if (typeof component === "undefined") {
        return null
    }
    if (!observerInject) {
        return component()
    }
    // TODO: remove in next major
    console.warn(
        "<Observer inject=.../> is no longer supported. Please use inject on the enclosing component instead"
    )
    const InjectComponent = inject(observerInject)(component)
    return <InjectComponent />
})

Observer.displayName = "Observer"

const ObserverPropsCheck = (props, key, componentName, location, propFullName) => {
    const extraKey = key === "children" ? "render" : "children"
    if (typeof props[key] === "function" && typeof props[extraKey] === "function") {
        return new Error(
            "Invalid prop,do not use children and render in the same time in`" + componentName
        )
    }

    if (typeof props[key] === "function" || typeof props[extraKey] === "function") {
        return
    }
    return new Error(
        "Invalid prop `" +
            propFullName +
            "` of type `" +
            typeof props[key] +
            "` supplied to" +
            " `" +
            componentName +
            "`, expected `function`."
    )
}

Observer.propTypes = {
    render: ObserverPropsCheck,
    children: ObserverPropsCheck
}
<commit_msg>Added open question<commit_after>import React, { Component, PureComponent, forwardRef } from "react"
import hoistStatics from "hoist-non-react-statics"
import { createAtom, Reaction, _allowStateChanges, $mobx } from "mobx"
import { findDOMNode as baseFindDOMNode } from "react-dom"

import EventEmitter from "./utils/EventEmitter"
import inject from "./inject"
import { patch as newPatch, newSymbol } from "./utils/utils"

const mobxAdminProperty = $mobx || "$mobx"
const mobxIsUnmounted = newSymbol("isUnmounted")

/**
 * dev tool support
 */
let isDevtoolsEnabled = false

let isUsingStaticRendering = false

let warnedAboutObserverInjectDeprecation = false

// WeakMap<Node, Object>;
export const componentByNodeRegistry = typeof WeakMap !== "undefined" ? new WeakMap() : undefined
export const renderReporter = new EventEmitter()

const skipRenderKey = newSymbol("skipRender")
const isForcingUpdateKey = newSymbol("isForcingUpdate")

// Using react-is had some issues (and operates on elements, not on types), see #608 / #609
const ReactForwardRefSymbol =
    typeof forwardRef === "function" && forwardRef((_props, _ref) => {})["$$typeof"]

/**
 * Helper to set `prop` to `this` as non-enumerable (hidden prop)
 * @param target
 * @param prop
 * @param value
 */
function setHiddenProp(target, prop, value) {
    if (!Object.hasOwnProperty.call(target, prop)) {
        Object.defineProperty(target, prop, {
            enumerable: false,
            configurable: true,
            writable: true,
            value
        })
    } else {
        target[prop] = value
    }
}

function findDOMNode(component) {
    if (baseFindDOMNode) {
        try {
            return baseFindDOMNode(component)
        } catch (e) {
            // findDOMNode will throw in react-test-renderer, see:
            // See https://github.com/mobxjs/mobx-react/issues/216
            // Is there a better heuristic?
            return null
        }
    }
    return null
}

function reportRendering(component) {
    const node = findDOMNode(component)
    if (node && componentByNodeRegistry) componentByNodeRegistry.set(node, component)

    renderReporter.emit({
        event: "render",
        renderTime: component.__$mobRenderEnd - component.__$mobRenderStart,
        totalTime: Date.now() - component.__$mobRenderStart,
        component: component,
        node: node
    })
}

export function trackComponents() {
    if (typeof WeakMap === "undefined")
        throw new Error("[mobx-react] tracking components is not supported in this browser.")
    if (!isDevtoolsEnabled) isDevtoolsEnabled = true
}

export function useStaticRendering(useStaticRendering) {
    isUsingStaticRendering = useStaticRendering
}

/**
 * Errors reporter
 */

export const errorsReporter = new EventEmitter()

/**
 * Utilities
 */

function patch(target, funcName) {
    newPatch(target, funcName, reactiveMixin[funcName])
}

function shallowEqual(objA, objB) {
    //From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
    if (is(objA, objB)) return true
    if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
        return false
    }
    const keysA = Object.keys(objA)
    const keysB = Object.keys(objB)
    if (keysA.length !== keysB.length) return false
    for (let i = 0; i < keysA.length; i++) {
        if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
            return false
        }
    }
    return true
}

function is(x, y) {
    // From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
    if (x === y) {
        return x !== 0 || 1 / x === 1 / y
    } else {
        return x !== x && y !== y
    }
}

function makeComponentReactive(render) {
    if (isUsingStaticRendering === true) return render.call(this)

    function reactiveRender() {
        isRenderingPending = false
        let exception = undefined
        let rendering = undefined
        reaction.track(() => {
            if (isDevtoolsEnabled) {
                this.__$mobRenderStart = Date.now()
            }
            try {
                rendering = _allowStateChanges(false, baseRender)
            } catch (e) {
                exception = e
            }
            if (isDevtoolsEnabled) {
                this.__$mobRenderEnd = Date.now()
            }
        })
        if (exception) {
            errorsReporter.emit(exception)
            throw exception
        }
        return rendering
    }

    // Generate friendly name for debugging
    const initialName =
        this.displayName ||
        this.name ||
        (this.constructor && (this.constructor.displayName || this.constructor.name)) ||
        "<component>"
    const rootNodeID =
        (this._reactInternalInstance && this._reactInternalInstance._rootNodeID) ||
        (this._reactInternalInstance && this._reactInternalInstance._debugID) ||
        (this._reactInternalFiber && this._reactInternalFiber._debugID)
    /**
     * If props are shallowly modified, react will render anyway,
     * so atom.reportChanged() should not result in yet another re-render
     */
    setHiddenProp(this, skipRenderKey, false)
    /**
     * forceUpdate will re-assign this.props. We don't want that to cause a loop,
     * so detect these changes
     */
    setHiddenProp(this, isForcingUpdateKey, false)

    // wire up reactive render
    const baseRender = render.bind(this)
    let isRenderingPending = false

    const reaction = new Reaction(`${initialName}#${rootNodeID}.render()`, () => {
        if (!isRenderingPending) {
            // N.B. Getting here *before mounting* means that a component constructor has side effects (see the relevant test in misc.js)
            // This unidiomatic React usage but React will correctly warn about this so we continue as usual
            // See #85 / Pull #44
            isRenderingPending = true
            if (typeof this.componentWillReact === "function") this.componentWillReact() // TODO: wrap in action?
            if (this[mobxIsUnmounted] !== true) {
                // If we are unmounted at this point, componentWillReact() had a side effect causing the component to unmounted
                // TODO: remove this check? Then react will properly warn about the fact that this should not happen? See #73
                // However, people also claim this might happen during unit tests..
                let hasError = true
                try {
                    setHiddenProp(this, isForcingUpdateKey, true)
                    if (!this[skipRenderKey]) Component.prototype.forceUpdate.call(this)
                    hasError = false
                } finally {
                    setHiddenProp(this, isForcingUpdateKey, false)
                    if (hasError) reaction.dispose()
                }
            }
        }
    })
    reaction.reactComponent = this
    reactiveRender[mobxAdminProperty] = reaction
    this.render = reactiveRender
    return reactiveRender.call(this)
}

/**
 * ReactiveMixin
 */
const reactiveMixin = {
    componentWillUnmount: function() {
        if (isUsingStaticRendering === true) return
        this.render[mobxAdminProperty] && this.render[mobxAdminProperty].dispose()
        this[mobxIsUnmounted] = true
        if (isDevtoolsEnabled) {
            const node = findDOMNode(this)
            if (node && componentByNodeRegistry) {
                componentByNodeRegistry.delete(node)
            }
            renderReporter.emit({
                event: "destroy",
                component: this,
                node: node
            })
        }
    },

    componentDidMount: function() {
        if (isDevtoolsEnabled) {
            reportRendering(this)
        }
    },

    componentDidUpdate: function() {
        if (isDevtoolsEnabled) {
            reportRendering(this)
        }
    },

    shouldComponentUpdate: function(nextProps, nextState) {
        if (isUsingStaticRendering) {
            console.warn(
                "[mobx-react] It seems that a re-rendering of a React component is triggered while in static (server-side) mode. Please make sure components are rendered only once server-side."
            )
        }
        // update on any state changes (as is the default)
        if (this.state !== nextState) {
            return true
        }
        // update if props are shallowly not equal, inspired by PureRenderMixin
        // we could return just 'false' here, and avoid the `skipRender` checks etc
        // however, it is nicer if lifecycle events are triggered like usually,
        // so we return true here if props are shallowly modified.
        return !shallowEqual(this.props, nextProps)
    }
}

function makeObservableProp(target, propName) {
    const valueHolderKey = newSymbol(`reactProp_${propName}_valueHolder`)
    const atomHolderKey = newSymbol(`reactProp_${propName}_atomHolder`)
    function getAtom() {
        if (!this[atomHolderKey]) {
            setHiddenProp(this, atomHolderKey, createAtom("reactive " + propName))
        }
        return this[atomHolderKey]
    }
    Object.defineProperty(target, propName, {
        configurable: true,
        enumerable: true,
        get: function() {
            getAtom.call(this).reportObserved()
            return this[valueHolderKey]
        },
        set: function set(v) {
            if (!this[isForcingUpdateKey] && !shallowEqual(this[valueHolderKey], v)) {
                setHiddenProp(this, valueHolderKey, v)
                setHiddenProp(this, skipRenderKey, true)
                getAtom.call(this).reportChanged()
                setHiddenProp(this, skipRenderKey, false)
            } else {
                setHiddenProp(this, valueHolderKey, v)
            }
        }
    })
}

/**
 * Observer function / decorator
 */
export function observer(arg1, arg2) {
    if (typeof arg1 === "string") {
        throw new Error("Store names should be provided as array")
    }
    if (Array.isArray(arg1)) {
        // TODO: remove in next major
        // component needs stores
        if (!warnedAboutObserverInjectDeprecation) {
            warnedAboutObserverInjectDeprecation = true
            console.warn(
                'Mobx observer: Using observer to inject stores is deprecated since 4.0. Use `@inject("store1", "store2") @observer ComponentClass` or `inject("store1", "store2")(observer(componentClass))` instead of `@observer(["store1", "store2"]) ComponentClass`'
            )
        }
        if (!arg2) {
            // invoked as decorator
            return componentClass => observer(arg1, componentClass)
        } else {
            return inject.apply(null, arg1)(observer(arg2))
        }
    }
    const componentClass = arg1

    if (componentClass.isMobxInjector === true) {
        console.warn(
            "Mobx observer: You are trying to use 'observer' on a component that already has 'inject'. Please apply 'observer' before applying 'inject'"
        )
    }
    if (componentClass.__proto__ === PureComponent) {
        console.warn(
            "Mobx observer: You are using 'observer' on React.PureComponent. These two achieve two opposite goals and should not be used together"
        )
    }

    // Unwrap forward refs into `<Observer>` component
    // we need to unwrap the render, because it is the inner render that needs to be tracked,
    // not the ForwardRef HoC
    if (ReactForwardRefSymbol && componentClass["$$typeof"] === ReactForwardRefSymbol) {
        const baseRender = componentClass.render
        if (typeof baseRender !== "function")
            throw new Error("render property of ForwardRef was not a function")
        // TODO: do we need to hoist statics from baseRender to the forward ref?
        return forwardRef(function ObserverForwardRef() {
            return <Observer>{() => baseRender.apply(undefined, arguments)}</Observer>
        })
    }

    // Stateless function component:
    // If it is function but doesn't seem to be a react class constructor,
    // wrap it to a react class automatically
    if (
        typeof componentClass === "function" &&
        (!componentClass.prototype || !componentClass.prototype.render) &&
        !componentClass.isReactClass &&
        !Component.isPrototypeOf(componentClass)
    ) {
        const observerComponent = observer(
            class extends Component {
                static displayName = componentClass.displayName || componentClass.name
                static contextTypes = componentClass.contextTypes
                static propTypes = componentClass.propTypes
                static defaultProps = componentClass.defaultProps
                render() {
                    return componentClass.call(this, this.props, this.context)
                }
            }
        )
        hoistStatics(observerComponent, componentClass)
        return observerComponent
    }

    if (!componentClass) {
        throw new Error("Please pass a valid component to 'observer'")
    }

    const target = componentClass.prototype || componentClass
    mixinLifecycleEvents(target)
    componentClass.isMobXReactObserver = true
    makeObservableProp(target, "props")
    makeObservableProp(target, "state")
    const baseRender = target.render
    target.render = function() {
        return makeComponentReactive.call(this, baseRender)
    }
    return componentClass
}

function mixinLifecycleEvents(target) {
    ;["componentDidMount", "componentWillUnmount", "componentDidUpdate"].forEach(function(
        funcName
    ) {
        patch(target, funcName)
    })
    if (!target.shouldComponentUpdate) {
        target.shouldComponentUpdate = reactiveMixin.shouldComponentUpdate
    } else {
        if (target.shouldComponentUpdate !== reactiveMixin.shouldComponentUpdate) {
            // TODO: make throw in next major
            console.warn(
                "Use `shouldComponentUpdate` in an `observer` based component breaks the behavior of `observer` and might lead to unexpected results. Manually implementing `sCU` should not be needed when using mobx-react."
            )
        }
    }
}

export const Observer = observer(({ children, inject: observerInject, render }) => {
    const component = children || render
    if (typeof component === "undefined") {
        return null
    }
    if (!observerInject) {
        return component()
    }
    // TODO: remove in next major
    console.warn(
        "<Observer inject=.../> is no longer supported. Please use inject on the enclosing component instead"
    )
    const InjectComponent = inject(observerInject)(component)
    return <InjectComponent />
})

Observer.displayName = "Observer"

const ObserverPropsCheck = (props, key, componentName, location, propFullName) => {
    const extraKey = key === "children" ? "render" : "children"
    if (typeof props[key] === "function" && typeof props[extraKey] === "function") {
        return new Error(
            "Invalid prop,do not use children and render in the same time in`" + componentName
        )
    }

    if (typeof props[key] === "function" || typeof props[extraKey] === "function") {
        return
    }
    return new Error(
        "Invalid prop `" +
            propFullName +
            "` of type `" +
            typeof props[key] +
            "` supplied to" +
            " `" +
            componentName +
            "`, expected `function`."
    )
}

Observer.propTypes = {
    render: ObserverPropsCheck,
    children: ObserverPropsCheck
}
<|endoftext|>


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

var f           = require('d3-format');
var Handlebars  = require('handlebars');
var Moment      = require('moment');
var removemd    = require('remove-markdown');

var Metalsmith  = require('metalsmith');
var collections = require('metalsmith-collections');
var layouts     = require('metalsmith-layouts');
var markdown    = require('metalsmith-markdown');
var permalinks  = require('metalsmith-permalinks');
var sass        = require('metalsmith-sass');
var serve       = require('metalsmith-serve');
var tags        = require('metalsmith-tags');
var watch       = require('metalsmith-watch');
var wordcount   = require('metalsmith-word-count');

// partial definitions
Handlebars.registerPartial('citation', fs.readFileSync(__dirname + '/layouts/partials/citation.hbt').toString());
Handlebars.registerPartial('footer', fs.readFileSync(__dirname + '/layouts/partials/footer.hbt').toString());
Handlebars.registerPartial('head', fs.readFileSync(__dirname + '/layouts/partials/head.hbt').toString());
Handlebars.registerPartial('header', fs.readFileSync(__dirname + '/layouts/partials/header.hbt').toString());
Handlebars.registerPartial('list', fs.readFileSync(__dirname + '/layouts/partials/list.hbt').toString());
Handlebars.registerPartial('postdata', fs.readFileSync(__dirname + '/layouts/partials/postdata.hbt').toString());
Handlebars.registerPartial('nav', fs.readFileSync(__dirname + '/layouts/partials/nav.hbt').toString());
Handlebars.registerPartial('warning', fs.readFileSync(__dirname + '/layouts/partials/warning.hbt').toString());

// helper definitions
Handlebars.registerHelper('humanise', function(num) {
    // takes a number and then uses d3-format to render it in a reasonable
    // and more human readable form.
    return (f.format('.2s')(num));
});

Handlebars.registerHelper('moment', function(date, format) {
    // takes a date and formats it appropriately
    return Moment(date).format(format);
});

Handlebars.registerHelper('shown', function (from, to, context, options){
    var item = "";
    for (var i = from, j = to; i <= j; i++) {
        item = item + options.fn(context[i]);
    }
    return item;
});

// helpers for metalsmith
var excerpt = function(options) {
    // creates excerpts from the markdown using the first para that is actually
    // a paragraph of contnet not an image etc.
    return (function(files, metalsmith, done) {
        for (var file in files) {
            // just look at markdown files.
            if (file.endsWith(".md")) {
                if (! files[file].excerpt) {
                    var contents = files[file].contents.toString();
                    var patt = /^\w.+?\n/m;
                    var m = patt.exec(contents);
                    if (m) {
                        files[file].excerpt = removemd(m[0]);
                    }
                }
            }
        }
        done();
    });
};

var captioner = function(options) {

    options = options || {};

    var filetypes = options.fileExtension || ".html";

    return (function(files, metalsmith, done) {
        for (var file in files) {
            if (file.endsWith(filetypes)) {
                // we have a markdown file
                // TODO fix this.
                console.log(file);
                var contents = files[file].contents.toString();
                var patt = /img.+\/\>/m;
                var m = patt.exec(contents);
                console.log(m);
            }
        }
        done();
    });
};

var debug = function(options) {
    return (function(files, metalsmith, done) {
        for (var file in files) {
            console.log(file);
        }
        done();
    });
};

Metalsmith(__dirname)
    .metadata({
        site: {
            url: "http://ajfisher.me",
        }
    })
    .use(watch({
        paths: {
            "$(source)/**/*": "**/*.md",
            "layouts/**/*": "**/*.md",
            "index.js": "**/*.md",
            "src/css/**/*": "**/*",
        }
    }))
    .use(collections({
        pages: {
            pattern: "content/pages/*.md",
			refer: false,
        },
        posts: {
            pattern: "content/posts/*.md",
            sortBy: "date",
            reverse: true,
            refer: false,
        },
        featured: {
            sortBy: "date",
            reverse: true,
            refer: false,
        }
    }))
    .use(excerpt())
    .use(markdown())
    .use(captioner())
    .use(wordcount({
        metaKeyCount: "wordcount",
        metaKeyReadingTime: "readingtime",
        seconds: false,
        raw: true,
    }))
    .use(permalinks({
        pattern: ":slug",
        linksets: [{
            match: {collection: "posts"},
            pattern: ":date/:slug",
        },
        {
            match: { collection: "pages"},
            pattern: ":slug",
        }],
    }))
    .use(tags({
        handle: 'tags',
        path: 'tagged/:tag/index.html',
        layout: 'blog.hbt',
        sortBy: 'date',
        reverse: true,
    }))
    .use(layouts({
        engine: "handlebars",
        directory: "./layouts",
        partials: "./layouts/partials",
    }))
    .source("./src")
    .destination("./build")
    .use(sass({
        outputDir: 'css/',
        watch: 'src/css/**/*',
    }))
    .use(serve({
        cache: 0,
        verbose: true,
        host: '0.0.0.0',
    }))
    .build(function(err) {
        if (err) {
            console.log(err);
        } else {
            console.log("Site built correctly");
        }
    });
<commit_msg>start of image sorting stuff<commit_after>var fs = require('fs');

var f           = require('d3-format');
var Handlebars  = require('handlebars');
var Moment      = require('moment');
var removemd    = require('remove-markdown');

var Metalsmith  = require('metalsmith');
var collections = require('metalsmith-collections');
var layouts     = require('metalsmith-layouts');
var markdown    = require('metalsmith-markdown');
var permalinks  = require('metalsmith-permalinks');
var sass        = require('metalsmith-sass');
var serve       = require('metalsmith-serve');
var tags        = require('metalsmith-tags');
var watch       = require('metalsmith-watch');
var wordcount   = require('metalsmith-word-count');

// partial definitions
Handlebars.registerPartial('citation', fs.readFileSync(__dirname + '/layouts/partials/citation.hbt').toString());
Handlebars.registerPartial('footer', fs.readFileSync(__dirname + '/layouts/partials/footer.hbt').toString());
Handlebars.registerPartial('head', fs.readFileSync(__dirname + '/layouts/partials/head.hbt').toString());
Handlebars.registerPartial('header', fs.readFileSync(__dirname + '/layouts/partials/header.hbt').toString());
Handlebars.registerPartial('list', fs.readFileSync(__dirname + '/layouts/partials/list.hbt').toString());
Handlebars.registerPartial('postdata', fs.readFileSync(__dirname + '/layouts/partials/postdata.hbt').toString());
Handlebars.registerPartial('nav', fs.readFileSync(__dirname + '/layouts/partials/nav.hbt').toString());
Handlebars.registerPartial('warning', fs.readFileSync(__dirname + '/layouts/partials/warning.hbt').toString());

// helper definitions
Handlebars.registerHelper('humanise', function(num) {
    // takes a number and then uses d3-format to render it in a reasonable
    // and more human readable form.
    return (f.format('.2s')(num));
});

Handlebars.registerHelper('moment', function(date, format) {
    // takes a date and formats it appropriately
    return Moment(date).format(format);
});

Handlebars.registerHelper('shown', function (from, to, context, options){
    var item = "";
    for (var i = from, j = to; i <= j; i++) {
        item = item + options.fn(context[i]);
    }
    return item;
});

// helpers for metalsmith
var excerpt = function(options) {
    // creates excerpts from the markdown using the first para that is actually
    // a paragraph of contnet not an image etc.
    return (function(files, metalsmith, done) {
        for (var file in files) {
            // just look at markdown files.
            if (file.endsWith(".md")) {
                if (! files[file].excerpt) {
                    var contents = files[file].contents.toString();
                    var patt = /^\w.+?\n/m;
                    var m = patt.exec(contents);
                    if (m) {
                        files[file].excerpt = removemd(m[0]);
                    }
                }
            }
        }
        done();
    });
};

var captioner = function(options) {

    options = options || {};

    var filetypes = options.fileExtension || ".md";

    return (function(files, metalsmith, done) {
        for (var file in files) {
            if (file.endsWith(filetypes)) {
                // we have a markdown file
                // TODO fix this.
                console.log(file);
                console.log("------");
                var contents = files[file].contents.toString();
                var patt = /\!\[(.+?)\]\((.*)\)/mg;
                while (m = patt.exec(contents)) {
                    console.log("...");
                    console.log(m[0]);
                    console.log(m[1]);
                    console.log(m[2]);
                }
            }
        }
        done();
    });
};

var debug = function(options) {
    return (function(files, metalsmith, done) {
        for (var file in files) {
            console.log(file);
        }
        done();
    });
};

Metalsmith(__dirname)
    .metadata({
        site: {
            url: "http://ajfisher.me",
        }
    })
    .use(watch({
        paths: {
            "$(source)/**/*": "**/*.md",
            "layouts/**/*": "**/*.md",
            "index.js": "**/*.md",
            "src/css/**/*": "**/*",
        }
    }))
    .use(collections({
        pages: {
            pattern: "content/pages/*.md",
			refer: false,
        },
        posts: {
            pattern: "content/posts/*.md",
            sortBy: "date",
            reverse: true,
            refer: false,
        },
        featured: {
            sortBy: "date",
            reverse: true,
            refer: false,
        }
    }))
    .use(excerpt())
    .use(captioner())
    .use(markdown())
    .use(wordcount({
        metaKeyCount: "wordcount",
        metaKeyReadingTime: "readingtime",
        seconds: false,
        raw: true,
    }))
    .use(permalinks({
        pattern: ":slug",
        linksets: [{
            match: {collection: "posts"},
            pattern: ":date/:slug",
        },
        {
            match: { collection: "pages"},
            pattern: ":slug",
        }],
    }))
    .use(tags({
        handle: 'tags',
        path: 'tagged/:tag/index.html',
        layout: 'blog.hbt',
        sortBy: 'date',
        reverse: true,
    }))
    .use(layouts({
        engine: "handlebars",
        directory: "./layouts",
        partials: "./layouts/partials",
    }))
    .source("./src")
    .destination("./build")
    .use(sass({
        outputDir: 'css/',
        watch: 'src/css/**/*',
    }))
    .use(serve({
        cache: 0,
        verbose: true,
        host: '0.0.0.0',
    }))
    .build(function(err) {
        if (err) {
            console.log(err);
        } else {
            console.log("Site built correctly");
        }
    });
<|endoftext|>


<commit_before>QUnit.module("streams", function() {
	domvm.config({
		stream: {
			val: function(v, accum) {
				if (flyd.isStream(v)) {
					accum.push(v);
					return v();
				}
				else
					return v;
			},
			on: function(accum, vm) {
				let calls = 0;

				const s = flyd.combine(function() {
					if (++calls == 2) {
						vm.redraw();
						s.end(true);
					}
				}, accum);

				return s;
			},
			off: function(s) {
				s.end(true);
			}
		}
	});

	QUnit.test('render', function(assert) {
		function View() {
			return function() {
				return el("div", {style: {background: color}, foo: attr}, body);
			}
		}

		var color = flyd.stream("red");
		var attr = flyd.stream("bar");
		var body = flyd.stream("hello");
		var data = flyd.stream([]);
		var data2 = flyd.stream([]);

		instr.start();
		var vm = domvm.createView(View, data).mount(testyDiv);
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { createElement: 1, textContent: 1, insertBefore: 1, setAttribute: 1 });

		instr.start();
		color("blue");
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		data({});
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		vm.update(data2);
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		vm.update({});
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		vm.update(data);
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		vm.unmount();
	});
});<commit_msg>[tests] move stream adapter setup into QUnit module 'before' hook (#198)<commit_after>var streamHooks = {
	before: function() {
		domvm.config({
			stream: {
				val: function(v, accum) {
					if (flyd.isStream(v)) {
						accum.push(v);
						return v();
					}
					else
						return v;
				},
				on: function(accum, vm) {
					let calls = 0;

					const s = flyd.combine(function() {
						if (++calls == 2) {
							vm.redraw();
							s.end(true);
						}
					}, accum);

					return s;
				},
				off: function(s) {
					s.end(true);
				}
			}
		});
	}
};

QUnit.module("streams", streamHooks, function() {
	QUnit.test('render', function(assert) {
		function View() {
			return function() {
				return el("div", {style: {background: color}, foo: attr}, body);
			}
		}

		var color = flyd.stream("red");
		var attr = flyd.stream("bar");
		var body = flyd.stream("hello");
		var data = flyd.stream([]);
		var data2 = flyd.stream([]);

		instr.start();
		var vm = domvm.createView(View, data).mount(testyDiv);
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { createElement: 1, textContent: 1, insertBefore: 1, setAttribute: 1 });

		instr.start();
		color("blue");
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		data({});
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		vm.update(data2);
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		vm.update({});
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		instr.start();
		vm.update(data);
		var callCounts = instr.end();

		var expcHtml = '
hello
';
		evalOut(assert, vm.node.el, vm.html(), expcHtml, callCounts, { });

		vm.unmount();
	});
});<|endoftext|>


<commit_before>'use strict';

const components = require('../../components.json');
const execSync = require('child_process').execSync;
const existsSync = require('fs').existsSync;
const path = require('path');

let componentPaths = [];

delete components.index;
delete components.font;

Object.keys(components).forEach(key => {
  const filePath = path.join(__dirname, `../../packages/${key}/cooking.conf.js`);

  if (existsSync(filePath)) {
    componentPaths.push(`packages/${key}/cooking.conf.js`);
  }
});

const paths = componentPaths.join(',');
const cli = `node_modules/.bin/cooking build -c ${paths} -p`;

execSync(cli, {
  stdio: 'inherit'
});
<commit_msg>fix : this didn't run on windows<commit_after>'use strict';

const components = require('../../components.json');
const execSync = require('child_process').execSync;
const existsSync = require('fs').existsSync;
const path = require('path');

let componentPaths = [];

delete components.index;
delete components.font;

Object.keys(components).forEach(key => {
  const filePath = path.join(__dirname, `../../packages/${key}/cooking.conf.js`);

  if (existsSync(filePath)) {
    componentPaths.push(`packages/${key}/cooking.conf.js`);
  }
});

const paths = componentPaths.join(',');
const cli = path.join('node_modules', '.bin', 'cooking') + ` build -c ${paths} -p`;

execSync(cli, {
  stdio: 'inherit'
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

var makeTable = require('./makeTable.js')
var fs = require('fs')

var KEY = process.argv[2]
var save = false

if (process.argv[3] && process.argv[3].match("--save")) {
  save = true
}

if (KEY && !save) {
  makeTable(KEY, function callback(err, table) {
    if (err != "null") return console.log(err)

    console.log(table)
  })
}

if (KEY && save) {
  makeTable(KEY, function callback(err, table) {
    if (err != "null") return console.log(err)

    fs.writeFile('table.md', table.toString(), function (err) {
      if (err) return console.log(err)
    })
  })
}

if (!KEY) {
  return console.log("To use: `$ sheetdown SPREADSHEET KEY --save`\n" +
                     "Or: `$ sheetdown SPREADSHEETKEY | pbcopy")
}
<commit_msg>Full URL support<commit_after>#!/usr/bin/env node

var makeTable = require('./makeTable.js')
var fs = require('fs')

var KEY = process.argv[2]
if (KEY.toLowerCase().indexOf("key=") > 0 ) {
  var re = /key=([a-zA-Z0-9+]+)/;
  var VAL = KEY.match(re);
  KEY = VAL;
}

var save = false

if (process.argv[3] && process.argv[3].match("--save")) {
  save = true
}

if (KEY && !save) {
  makeTable(KEY, function callback(err, table) {
    if (err != "null") return console.log(err)

    console.log(table)
  })
}

if (KEY && save) {
  makeTable(KEY, function callback(err, table) {
    if (err != "null") return console.log(err)

    fs.writeFile('table.md', table.toString(), function (err) {
      if (err) return console.log(err)
    })
  })
}

if (!KEY) {
  return console.log("To use: `$ sheetdown SPREADSHEET KEY --save`\n" +
                     "Or: `$ sheetdown SPREADSHEETKEY | pbcopy")
}
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var connect = require('connect')
  , assert = require('assert')
  , should = require('should')
  , http = require('http');

/**
 * Path to ./test/fixtures/
 */

var fixturesPath = __dirname + '/fixtures';

var app = connect.createServer(
  connect.static(fixturesPath)
);

var app2 = connect.createServer(
  connect.static(fixturesPath + '/foo/bar/../../')
);

module.exports = {
   'test valid file': function(){
     assert.response(app,
       { url: '/user.json' },
       function(res){
         res.statusCode.should.equal(200);
         JSON.parse(res.body).should.eql({ name: 'tj', email: 'tj@vision-media.ca' });
         res.headers.should.have.property('content-length', '55');
         res.headers.should.have.property('cache-control', 'public, max-age=0');
         res.headers.should.have.property('last-modified');
         res.headers.should.have.property('etag');
     });
   },

  'test maxAge': function(){
    var app = connect.createServer(
      connect.static(fixturesPath, { maxAge: 60000 })
    );

    assert.response(app,
      { url: '/user.json' },
      function(res){
        res.statusCode.should.equal(200);
        res.headers.should.have.property('cache-control', 'public, max-age=60');
    });
  },

  'test url encoding': function(){
    assert.response(app,
      { url: '/some%20text.txt' },
      { body: 'whoop', status: 200 });
  },

  'test index.html support': function(){
    assert.response(app,
      { url: '/' },
      { body: '
Wahoo!
'
      , status: 200
      , headers: {
        'Content-Type': 'text/html; charset=UTF-8'
      }});
  },

  'test index.html support when missing': function(){
    var app = connect.createServer(
      connect.static(__dirname)
    );

    assert.response(app,
      { url: '/' },
      { body: 'Cannot GET /', status: 404 });
  },

  'test invalid file': function(){
    assert.response(app,
      { url: '/foo.json' },
      { body: 'Cannot GET /foo.json', status: 404 });
  },

  'test directory': function(){
    assert.response(app,
      { url: '/fixtures' },
      { body: 'Cannot GET /fixtures', status: 404 });
  },

  'test forbidden': function(){
    assert.response(app,
      { url: '/../favicon.test.js' },
      { body: 'Forbidden', status: 403 });
  },

  'test forbidden urlencoded': function(){
    assert.response(app,
      { url: '/%2e%2e/favicon.test.js' },
      { body: 'Forbidden', status: 403 });
  },

  'test relative': function(){
    assert.response(app,
      { url: '/foo/../foo.log' },
      { body: '127.0.0.1\n' });
  },

  'test relative root': function(){
    assert.response(app2,
      { url: '/foo/../foo.log' },
      { body: '127.0.0.1\n' });
  },

  'test 404 on hidden file': function(){
    assert.response(app,
      { url: '/.hidden' },
      { status: 404 });
  },

  'test "hidden" option': function(){
    var app = connect.createServer(
      connect.static(fixturesPath, { hidden: true })
    );

    assert.response(app,
      { url: '/.hidden' },
      { body: 'hidden\n' });
  },

  'test HEAD': function(){
    assert.response(app,
      { url: '/user.json', method: 'HEAD' },
      { status: 200, headers: { 'Content-Length': '55' }});
  },

  'test Range': function(){
    assert.response(app,
      { url: '/list', headers: { Range: 'bytes=0-4' }},
      { body: '12345', status: 206 });
  },

  'test Range 2': function(){
    assert.response(app,
      { url: '/list', headers: { Range: 'bytes=5-9' }},
      { body: '6789', status: 206 });
  },

  'test invalid Range': function(){
    assert.response(app,
      { url: '/list', headers: { Range: 'bytes=RAWR' }},
      { body: 'Requested Range Not Satisfiable', status: 416 });
  },

  'test callback': function(){
    var app = connect.createServer(
      function(req, res, next){
        connect.static.send(req, res, function(err){
          res.end('done');
        }, { path: req.url });
      }
    );

    assert.response(app,
      { url: '/list' },
      { body: 'done' });
  },

  'test If-Modified-Since modified': function(){
    assert.response(app,
      { url: '/list', headers: { 'If-Modified-Since': new Date('2000').toUTCString() }},
      { body: '123456789', status: 200 });
  },

  'test If-Modified-Since unmodified': function(){
    assert.response(app,
      { url: '/list', headers: { 'If-Modified-Since': new Date('2050').toUTCString() }},
      { body: '', status: 304 },
      function(res){
        Object.keys(res.headers).forEach(function(field){
          if (0 == field.indexOf('content')) {
            should.fail('failed to strip ' + field);
          }
        });
      });
  },

  'test ETag unmodified': function(){
    var app = connect.createServer(
      connect.static(fixturesPath)
    );

    app.listen(9898, function(){
      var options = { path: '/list', port: 9898, host: '127.0.0.1' };
      http.get(options, function(res){
        res.statusCode.should.equal(200);
        res.headers.should.have.property('etag');
        var etag = res.headers.etag;
        options.headers = { 'If-None-Match': etag };
        http.get(options, function(res){
          etag.should.equal(res.headers.etag);
          res.statusCode.should.equal(304);
          res.headers.should.not.have.property('content-length');
          res.headers.should.not.have.property('content-type');
          app.close();
        });
      });
    });
  },

  'test ETag multiple given, unmodified': function(){
    var app = connect.createServer(
      connect.static(fixturesPath)
    );

    app.listen(9899, function(){
      var options = { path: '/list', port: 9899, host: '127.0.0.1' };
      http.get(options, function(res){
        res.statusCode.should.equal(200);
        res.headers.should.have.property('etag');
        var etag = res.headers.etag;
        options.headers = { 'If-None-Match': 'foo, bar, ' + etag };
        http.get(options, function(res){
          etag.should.equal(res.headers.etag);
          res.statusCode.should.equal(304);
          res.headers.should.not.have.property('content-length');
          res.headers.should.not.have.property('content-type');
          app.close();
        });
      });
    });
  },

  'test custom mime type definition': function(){
    require('mime').define({ 'application/coffee-script': ['coffee'] });
    assert.response(app,
      { url: '/script.coffee' },
      { headers: { 'Content-Type': 'application/coffee-script' }});
  },

  'test do not override Content-Type header': function(){
     var app = connect.createServer(
       function(req, res, next){
         res.setHeader('Content-Type', 'text/bozo; charset=ISO-8859-1');
         next();
       },
       connect.static(fixturesPath)
     );

     assert.response(app,
       { url: '/' },
       { body: '
Wahoo!
'
       , status: 200
       , headers: {
         'Content-Type': 'text/bozo; charset=ISO-8859-1'
       }});
   },

   'test mime export': function(){
     connect.static.mime.define.should.be.a('function');
   }
};<commit_msg>fixed static tests<commit_after>
/**
 * Module dependencies.
 */

var connect = require('connect')
  , assert = require('assert')
  , should = require('should')
  , http = require('http');

/**
 * Path to ./test/fixtures/
 */

var fixturesPath = __dirname + '/fixtures';

var app = connect.createServer(
  connect.static(fixturesPath)
);

var app2 = connect.createServer(
  connect.static(fixturesPath + '/foo/bar/../../')
);

module.exports = {
   'test valid file': function(){
     assert.response(app,
       { url: '/user.json' },
       function(res){
         res.statusCode.should.equal(200);
         JSON.parse(res.body).should.eql({ name: 'tj', email: 'tj@vision-media.ca' });
         res.headers.should.have.property('content-length', '55');
         res.headers.should.have.property('cache-control', 'public, max-age=0');
         res.headers.should.have.property('last-modified');
         res.headers.should.have.property('etag');
     });
   },

  'test maxAge': function(){
    var app = connect.createServer(
      connect.static(fixturesPath, { maxAge: 60000 })
    );

    assert.response(app,
      { url: '/user.json' },
      function(res){
        res.statusCode.should.equal(200);
        res.headers.should.have.property('cache-control', 'public, max-age=60');
    });
  },

  'test url encoding': function(){
    assert.response(app,
      { url: '/some%20text.txt' },
      { body: 'whoop', status: 200 });
  },

  'test index.html support': function(){
    assert.response(app,
      { url: '/' },
      { body: '
Wahoo!
'
      , status: 200
      , headers: {
        'Content-Type': 'text/html; charset=UTF-8'
      }});
  },

  'test index.html support when missing': function(){
    var app = connect.createServer(
      connect.static(__dirname)
    );

    assert.response(app,
      { url: '/' },
      { body: 'Cannot GET /', status: 404 });
  },

  'test invalid file': function(){
    assert.response(app,
      { url: '/foo.json' },
      { body: 'Cannot GET /foo.json', status: 404 });
  },

  'test directory': function(){
    assert.response(app,
      { url: '/fixtures' },
      { body: 'Cannot GET /fixtures', status: 404 });
  },

  'test forbidden': function(){
    assert.response(app,
      { url: '/../favicon.test.js' },
      { body: 'Forbidden', status: 403 });
  },

  'test forbidden urlencoded': function(){
    assert.response(app,
      { url: '/%2e%2e/favicon.test.js' },
      { body: 'Forbidden', status: 403 });
  },

  'test relative': function(){
    assert.response(app,
      { url: '/foo/../some%20text.txt' },
      { body: 'whoop' });
  },

  'test relative root': function(){
    assert.response(app2,
      { url: '/foo/../some%20text.txt' },
      { body: 'whoop' });
  },

  'test 404 on hidden file': function(){
    assert.response(app,
      { url: '/.hidden' },
      { status: 404 });
  },

  'test "hidden" option': function(){
    var app = connect.createServer(
      connect.static(fixturesPath, { hidden: true })
    );

    assert.response(app,
      { url: '/.hidden' },
      { body: 'hidden\n' });
  },

  'test HEAD': function(){
    assert.response(app,
      { url: '/user.json', method: 'HEAD' },
      { status: 200, headers: { 'Content-Length': '55' }});
  },

  'test Range': function(){
    assert.response(app,
      { url: '/list', headers: { Range: 'bytes=0-4' }},
      { body: '12345', status: 206 });
  },

  'test Range 2': function(){
    assert.response(app,
      { url: '/list', headers: { Range: 'bytes=5-9' }},
      { body: '6789', status: 206 });
  },

  'test invalid Range': function(){
    assert.response(app,
      { url: '/list', headers: { Range: 'bytes=RAWR' }},
      { body: 'Requested Range Not Satisfiable', status: 416 });
  },

  'test callback': function(){
    var app = connect.createServer(
      function(req, res, next){
        connect.static.send(req, res, function(err){
          res.end('done');
        }, { path: req.url });
      }
    );

    assert.response(app,
      { url: '/list' },
      { body: 'done' });
  },

  'test If-Modified-Since modified': function(){
    assert.response(app,
      { url: '/list', headers: { 'If-Modified-Since': new Date('2000').toUTCString() }},
      { body: '123456789', status: 200 });
  },

  'test If-Modified-Since unmodified': function(){
    assert.response(app,
      { url: '/list', headers: { 'If-Modified-Since': new Date('2050').toUTCString() }},
      { body: '', status: 304 },
      function(res){
        Object.keys(res.headers).forEach(function(field){
          if (0 == field.indexOf('content')) {
            should.fail('failed to strip ' + field);
          }
        });
      });
  },

  'test ETag unmodified': function(){
    var app = connect.createServer(
      connect.static(fixturesPath)
    );

    app.listen(9898, function(){
      var options = { path: '/list', port: 9898, host: '127.0.0.1' };
      http.get(options, function(res){
        res.statusCode.should.equal(200);
        res.headers.should.have.property('etag');
        var etag = res.headers.etag;
        options.headers = { 'If-None-Match': etag };
        http.get(options, function(res){
          etag.should.equal(res.headers.etag);
          res.statusCode.should.equal(304);
          res.headers.should.not.have.property('content-length');
          res.headers.should.not.have.property('content-type');
          app.close();
        });
      });
    });
  },

  'test ETag multiple given, unmodified': function(){
    var app = connect.createServer(
      connect.static(fixturesPath)
    );

    app.listen(9899, function(){
      var options = { path: '/list', port: 9899, host: '127.0.0.1' };
      http.get(options, function(res){
        res.statusCode.should.equal(200);
        res.headers.should.have.property('etag');
        var etag = res.headers.etag;
        options.headers = { 'If-None-Match': 'foo, bar, ' + etag };
        http.get(options, function(res){
          etag.should.equal(res.headers.etag);
          res.statusCode.should.equal(304);
          res.headers.should.not.have.property('content-length');
          res.headers.should.not.have.property('content-type');
          app.close();
        });
      });
    });
  },

  'test custom mime type definition': function(){
    require('mime').define({ 'application/coffee-script': ['coffee'] });
    assert.response(app,
      { url: '/script.coffee' },
      { headers: { 'Content-Type': 'application/coffee-script' }});
  },

  'test do not override Content-Type header': function(){
     var app = connect.createServer(
       function(req, res, next){
         res.setHeader('Content-Type', 'text/bozo; charset=ISO-8859-1');
         next();
       },
       connect.static(fixturesPath)
     );

     assert.response(app,
       { url: '/' },
       { body: '
Wahoo!
'
       , status: 200
       , headers: {
         'Content-Type': 'text/bozo; charset=ISO-8859-1'
       }});
   },

   'test mime export': function(){
     connect.static.mime.define.should.be.a('function');
   }
};<|endoftext|>


<commit_before>/**
 * @providesModule Notifications
 */

'use strict';

import { NativeModules, DeviceEventEmitter } from 'react-native';

const { RNOneSignal } = NativeModules;

var Notifications = {
	onError: false,
	onNotificationOpened: false,

	loaded: false,
};

var _pendingNotifications = [];
var _notifHandlers = new Map();
var DEVICE_NOTIF_EVENT = 'remoteNotificationOpened';

Notifications.addEventListener = function(type: string, handler: Function) {
	var listener;
	if (type === 'notification') {
		console.log('Regsitered notification event listener at', Date.now());
		if (_pendingNotifications.length > 0) {
			console.log('Found pending notification!')
			var notification = _pendingNotifications.pop();
			handler(notification.message, notification.data, notification.isActive);
		}

		listener =  DeviceEventEmitter.addListener(
			DEVICE_NOTIF_EVENT,
			function(notifData) {
				console.log(notifData);
				var message = notifData.message;
				var data = (notifData.additionalData !== null && typeof notifData.additionalData === 'object') ? notifData.additionalData : JSON.parse(notifData.additionalData);
				var isActive = notifData.isActive;
				handler(message, data, isActive);
			}
		);
	}

	_notifHandlers.set(handler, listener);
};

Notifications.removeEventListener = function(type: string, handler: Function) {
	var listener = _notifHandlers.get(handler);
	if (!listener) {
		return;
	}
	listener.remove();
	_notifHandlers.delete(handler);
}

/**
 * Configure local and remote notifications
 * @param {Object}		options
 * @param {function}	options.onNotificationOpened - Fired when a remote notification is received.
 * @param {function} 	options.onError - None
 */
Notifications.configure = function(options: Object) {
	if ( typeof options.onError !== 'undefined' ) {
		this.onError = options.onError;
	}

	if ( typeof options.onNotificationOpened !== 'undefined' ) {
		this.onNotificationOpened = options.onNotificationOpened;
	}

	if ( this.loaded === false ) {
		this.addEventListener('notification', this._onNotificationOpened.bind(this));

		this.loaded = true;
	}
};

/* Unregister */
Notifications.unregister = function() {
	this.removeEventListener('notification', this._onNotificationOpened.bind(this));
};

Notifications._onNotificationOpened = function(message, data, isActive) {
	if ( this.onNotificationOpened === false ) {
		var notification = {message: message, data: data, isActive: isActive};
		_pendingNotifications.push(notification);
		return;
	}
	this.onNotificationOpened(message, data, isActive);
};

Notifications.sendTag = function(key, value) {
	RNOneSignal.sendTag(key, value);
};

Notifications.sendTags = function(tags) {
	RNOneSignal.sendTags(tags || {});
};

Notifications.getTags = function(next) {
	RNOneSignal.getTags(next);
}

Notifications.deleteTag = function(key) {
	RNOneSignal.deleteTag(key);
}

module.exports = Notifications;
<commit_msg>Cleaned code, supports only one listener at a time<commit_after>/**
 * @providesModule Notifications
 */

'use strict';

import { NativeModules, DeviceEventEmitter } from 'react-native';

const { RNOneSignal } = NativeModules;

var Notifications = {
	onError: false,
	onNotificationOpened: false,
};

var _pendingNotifications = [];
var _notifHandlers = new Map();
var DEVICE_NOTIF_EVENT = 'remoteNotificationOpened';

/**
 * Configure local and remote notifications
 * @param {Object}		options
 * @param {function}	options.onNotificationOpened - Fired when a remote notification is received.
 * @param {function} 	options.onError - None
 */
Notifications.configure = function(options: Object) {
	if ( typeof options.onError !== 'undefined' ) {
		this.onError = options.onError;
	}

	if ( typeof options.onNotificationOpened !== 'undefined' ) {
		this.onNotificationOpened = options.onNotificationOpened;

		if (_pendingNotifications.length > 0) {
			console.log('Found pending notification!')
			var notification = _pendingNotifications.pop();
			this._onNotificationOpened(notification.message, notification.data, notification.isActive);
		}
	}
};

/* Unregister */
Notifications.unregister = function() {
	this.onNotificationOpened = false;
};

Notifications._onNotificationOpened = function(message, data, isActive) {
	if ( this.onNotificationOpened === false ) {
		var notification = {message: message, data: data, isActive: isActive};
		_pendingNotifications.push(notification);
		return;
	}
	this.onNotificationOpened(message, data, isActive);
};

Notifications.sendTag = function(key, value) {
	RNOneSignal.sendTag(key, value);
};

Notifications.sendTags = function(tags) {
	RNOneSignal.sendTags(tags || {});
};

Notifications.getTags = function(next) {
	RNOneSignal.getTags(next);
}

Notifications.deleteTag = function(key) {
	RNOneSignal.deleteTag(key);
}

DeviceEventEmitter.addListener(DEVICE_NOTIF_EVENT, function(notifData) {
		var message = notifData.message;
		var data = (notifData.additionalData !== null && typeof notifData.additionalData === 'object') ? notifData.additionalData : JSON.parse(notifData.additionalData);
		var isActive = notifData.isActive;
		Notifications._onNotificationOpened(message, data, isActive);
	}
);

module.exports = Notifications;
<|endoftext|>


<commit_before>/*
 * syslog-test.js: Tests for instances of the Syslog transport
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENSE
 *
 */

var path = require('path'),
    vows = require('vows'),
    assert = require('assert'),
    winston = require('winston'),
    helpers = require('winston/test/helpers'),
    Syslog = require('../lib/winston-syslog').Syslog;

function assertSyslog(transport) {
  assert.instanceOf(transport, Syslog);
  assert.isFunction(transport.log);
  assert.isFunction(transport.connect);
}

function closeTopicInfo() {
  var transport = new winston.transports.Syslog(),
      logger = new winston.Logger({ transports: [transport] });

  logger.log('info', 'Test message to actually use socket');
  logger.remove(transport);

  return transport;
}

function closeTopicDebug() {
  var transport = new winston.transports.Syslog(),
      logger = new winston.Logger({ transports: [transport] });

  logger.log('debug', 'Test message to actually use socket');
  logger.remove(transport);

  return transport;
}

var transport = new Syslog();

vows.describe('winston-syslog').addBatch({
  'An instance of the Syslog Transport': {
    'should have the proper methods defined': function () {
      assertSyslog(transport);
    },
    'the log() method': helpers.testSyslogLevels(transport, 'should log messages to syslogd', function (ign, err, ok) {
      assert.isNull(ign);
      assert.isTrue(!err);
      assert.isTrue(ok);
      assert.equal(transport.queue.length, 0); // This is > 0 because winston-syslog.js line 124
    }),
    'on close after not really writing': {
      topic: closeTopicDebug,
      on: {
        closed: {
          'closes the socket': function (socket) {
            assert.isNull(socket);
          }
        }
      }
    },
    'on close after really writing': {
      topic: closeTopicInfo,
      on: {
        closed: {
          'closes the socket': function (socket) {
            assert.isNull(socket._handle);
          }
        }
      }
    }
  }
}).export(module);

//
// TODO: Close all the syslog connections so vows exits.
//
setTimeout(function () {
  process.exit(0);
}, 5000);
<commit_msg>[test] remove final timeout from syslog-test.js<commit_after>/*
 * syslog-test.js: Tests for instances of the Syslog transport
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENSE
 *
 */

var path = require('path'),
    vows = require('vows'),
    assert = require('assert'),
    winston = require('winston'),
    helpers = require('winston/test/helpers'),
    Syslog = require('../lib/winston-syslog').Syslog;

function assertSyslog(transport) {
  assert.instanceOf(transport, Syslog);
  assert.isFunction(transport.log);
  assert.isFunction(transport.connect);
}

function closeTopicInfo() {
  var transport = new winston.transports.Syslog(),
      logger = new winston.Logger({ transports: [transport] });

  logger.log('info', 'Test message to actually use socket');
  logger.remove(transport);

  return transport;
}

function closeTopicDebug() {
  var transport = new winston.transports.Syslog(),
      logger = new winston.Logger({ transports: [transport] });

  logger.log('debug', 'Test message to actually use socket');
  logger.remove(transport);

  return transport;
}

var transport = new Syslog();

vows.describe('winston-syslog').addBatch({
  'An instance of the Syslog Transport': {
    'should have the proper methods defined': function () {
      assertSyslog(transport);
    },
    'the log() method': helpers.testSyslogLevels(transport, 'should log messages to syslogd', function (ign, err, ok) {
      assert.isNull(ign);
      assert.isTrue(!err);
      assert.isTrue(ok);
      assert.equal(transport.queue.length, 0); // This is > 0 because winston-syslog.js line 124
    }),
    'on close after not really writing': {
      topic: closeTopicDebug,
      on: {
        closed: {
          'closes the socket': function (socket) {
            assert.isNull(socket);
          }
        }
      }
    },
    'on close after really writing': {
      topic: closeTopicInfo,
      on: {
        closed: {
          'closes the socket': function (socket) {
            assert.isNull(socket._handle);
          }
        }
      }
    }
  }
}).export(module);
<|endoftext|>


<commit_before>function FayeAuthentication(endpoint) {
  this._endpoint = endpoint || '/faye/auth';
}

FayeAuthentication.prototype.endpoint = function() {
  return (this._endpoint);
};

FayeAuthentication.prototype.outgoing = function(message, callback) {
  if (message.channel == '/meta/subscribe') {
    $.post(this.endpoint(), message, function(response) {
      message.signature = response.signature;
      callback(message);
    });
  }
  else
    callback(message);
};
<commit_msg>Let's be strict<commit_after>function FayeAuthentication(endpoint) {
  this._endpoint = endpoint || '/faye/auth';
}

FayeAuthentication.prototype.endpoint = function() {
  return (this._endpoint);
};

FayeAuthentication.prototype.outgoing = function(message, callback) {
  if (message.channel === '/meta/subscribe') {
    $.post(this.endpoint(), message, function(response) {
      message.signature = response.signature;
      callback(message);
    });
  }
  else
    callback(message);
};
<|endoftext|>


<commit_before>/*jshint indent:2, curly:true eqeqeq:true, immed:true, latedef:true,
newcap:true, noarg:true, regexp:true, undef:true, strict:true, trailing:true
white:true*/
/*global XT:true, XM:true, Backbone:true, _:true, console:true */

(function () {
  "use strict";

  /**
    @class

    @extends XM.Model
  */
  XM.Image = XM.Model.extend({
    /** @scope XM.Image.prototype */

    recordType: 'XM.ImageRelation'

  });

  /**
    @class

    @extends XM.Model
  */
  XM.ImageRelation = XM.Info.extend({
    /** @scope XM.ImageRelation.prototype */

    recordType: 'XM.ImageRelation',

    editableModel: 'XM.Image',

    numberKey: 'name'

  });

}());
<commit_msg>fixed up image model<commit_after>/*jshint indent:2, curly:true eqeqeq:true, immed:true, latedef:true,
newcap:true, noarg:true, regexp:true, undef:true, strict:true, trailing:true
white:true*/
/*global XT:true, XM:true, Backbone:true, _:true, console:true */

(function () {
  "use strict";

  /**
    @class

    @extends XM.Model
  */
  XM.Image = XM.Model.extend({
    /** @scope XM.Image.prototype */

    recordType: 'XM.Image'

  });

  /**
    @class

    @extends XM.Model
  */
  XM.ImageRelation = XM.Info.extend({
    /** @scope XM.ImageRelation.prototype */

    recordType: 'XM.ImageRelation',

    editableModel: 'XM.Image',

    numberKey: 'name'

  });

  // ..........................................................
  // COLLECTIONS
  //

  /**
    @class

    @extends XM.Collection
  */
  XM.ImageRelationCollection = XM.Collection.extend({
    /** @scope XM.ImageCollection.prototype */

    model: XM.ImageRelation

  });

}());
<|endoftext|>


<commit_before>'use strict';

var cmd = require('commander')
  .option('-b', '--browsers [browsers]', 'Comma separated list of browsers to test with.')
  .option('-h', '--host [host]', 'The host to listen on.')
  .option('-k', '--keepalive', 'Whether or not to keep the server alive.')
  .option('-p', '--port [port]', 'The port to listen on.')
  .parse(process.argv);

var browsers = 'Firefox';

if (!cmd.keepalive && cmd.browsers) {
  browsers = cmd.browsers;
}

module.exports = function (config) {
  config.set({
    basePath: '../..',

    browsers: browsers.split(','),

    files: [
      { pattern: '.tmp/run-unit-tests.js', included: true }
    ],

    frameworks: [
      'mocha',
      'chai'
    ],

    hostname: cmd.host || 'localhost',

    plugins: [
      'karma-chai',
      'karma-chrome-launcher',
      'karma-firefox-launcher',
      'karma-mocha'
    ],

    port: cmd.port || '9876',

    reporters: [
      'progress'
    ],

    singleRun: !cmd.keepalive
  });
};
<commit_msg>Remove redundant config.<commit_after><|endoftext|>


<commit_before>var request = require('request')
var split = require('split2')

module.exports = function(url, opts) {
  if (!opts) opts = {}
  if (typeof opts.retry !== 'number' && opts.retry !== false) opts.retry = 3000

  var dataBuf = ''
  var event = ''
  var id = ''
  var req
  var timeout

  var parse = split(function(line) {
    if (!line) {
      if (!dataBuf) return
      var data = dataBuf
      dataBuf = ''
      return {
        id : id,
        event : event,
        data : data
      }
    }
    if (line.indexOf('data: ') === 0) dataBuf += (dataBuf ? '\n' : '') + line.slice(6)
    if (line.indexOf('id: ') === 0) id = line.slice(4)
    if (line.indexOf('event: ') === 0) event = line.slice(6)

  })

  var connect = function() {
    dataBuf = ''
    req = request({url: url, headers: opts.headers})

    req.on('error', function(err) {
      if (!opts.retry) parse.emit('error', err)
    })

    req.on('complete', function() {
      if (destroyed) return

      if (!opts.retry) {
        destroyed = true
        return parse.end()
      }

      timeout = setTimeout(connect, opts.retry)
      parse.emit('retry')
    })

    req.pipe(parse, {end:false})
  }

  connect()

  var destroyed = false
  parse.destroy = function() {
    if (destroyed) return
    destroyed = true
    clearTimeout(timeout)
    if (req) req.abort()
    parse.emit('close')
  }

  return parse
}<commit_msg>Propagate 'response' event<commit_after>var request = require('request')
var split = require('split2')

module.exports = function(url, opts) {
  if (!opts) opts = {}
  if (typeof opts.retry !== 'number' && opts.retry !== false) opts.retry = 3000

  var dataBuf = ''
  var event = ''
  var id = ''
  var req
  var timeout

  var parse = split(function(line) {
    if (!line) {
      if (!dataBuf) return
      var data = dataBuf
      dataBuf = ''
      return {
        id : id,
        event : event,
        data : data
      }
    }
    if (line.indexOf('data: ') === 0) dataBuf += (dataBuf ? '\n' : '') + line.slice(6)
    if (line.indexOf('id: ') === 0) id = line.slice(4)
    if (line.indexOf('event: ') === 0) event = line.slice(6)

  })

  var connect = function() {
    dataBuf = ''
    req = request({url: url, headers: opts.headers})

    req.on('error', function(err) {
      if (!opts.retry) parse.emit('error', err)
    })

    req.on('complete', function() {
      if (destroyed) return

      if (!opts.retry) {
        destroyed = true
        return parse.end()
      }

      timeout = setTimeout(connect, opts.retry)
      parse.emit('retry')
    })

    req.on('response', function (res) {
      parse.emit('response', res);
    })

    req.pipe(parse, {end:false})
  }

  connect()

  var destroyed = false
  parse.destroy = function() {
    if (destroyed) return
    destroyed = true
    clearTimeout(timeout)
    if (req) req.abort()
    parse.emit('close')
  }

  return parse
}
<|endoftext|>