<commit_before>import React, { PropTypes } from 'react'
import mask from './mask.js'

const CurrencyInput = React.createClass({

    /**
     * Prop validation.
     * @see https://facebook.github.io/react/docs/component-specs.html#proptypes
     */
    propTypes: {
        onChange: PropTypes.func,
        value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        decimalSeparator: PropTypes.string,
        thousandSeparator: PropTypes.string,
        precision: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        inputType: PropTypes.string,
        allowNegative: PropTypes.bool,
        allowEmpty: PropTypes.bool,
        prefix: PropTypes.string,
        suffix: PropTypes.string
    },

    /**
     * Component lifecycle function.
     *
     * Invoked once and cached when the class is created. Values in the mapping will be set on this.props if that
     * prop is not specified by the parent component
     *
     * @see https://facebook.github.io/react/docs/component-specs.html#getdefaultprops
     */
    getDefaultProps() {
        return {
            onChange: function(maskValue, value, event) {/*no-op*/},
            value: '0',
            decimalSeparator: '.',
            thousandSeparator: ',',
            precision: '2',
            inputType: 'text',
            allowNegative: false,
            prefix: '',
            suffix: ''
        }
    },

    /**
     * General function used to cleanup and define the final props used for rendering
     * @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
     */
    prepareProps(props) {
        let customProps = {...props}; // babeljs converts to Object.assign, then polyfills.
        delete customProps.onChange;
        delete customProps.value;
        delete customProps.decimalSeparator;
        delete customProps.thousandSeparator;
        delete customProps.precision;
        delete customProps.inputType;
        delete customProps.allowNegative;
        delete customProps.allowEmpty;
        delete customProps.prefix;
        delete customProps.suffix;

        let initialValue = props.value;
        if (!initialValue) {
            initialValue = props.allowEmpty? null : '';
        }else{

            if (typeof initialValue == 'string') {
                // Some people, when confronted with a problem, think "I know, I'll use regular expressions."
                // Now they have two problems.

                // Strip out thousand separators, prefix, and suffix, etc.
                if (props.thousandSeparator === "."){
                    // special handle the . thousand separator
                    initialValue = initialValue.replace(/\./g, '');
                }

                if (props.decimalSeparator != "."){
                    // fix the decimal separator
                    initialValue = initialValue.replace(new RegExp(props.decimalSeparator, 'g'), '.');
                }

                //Strip out anything that is not a digit, -, or decimal separator
                initialValue = initialValue.replace(/[^0-9-.]/g, '');

                // now we can parse.
                initialValue = Number.parseFloat(initialValue);
            }
            initialValue = Number(initialValue).toLocaleString(undefined, {
                style                : 'decimal',
                minimumFractionDigits: props.precision,
                maximumFractionDigits: props.precision
            })

        }

        const { maskedValue, value } = mask(
            initialValue,
            props.precision,
            props.decimalSeparator,
            props.thousandSeparator,
            props.allowNegative,
            props.prefix,
            props.suffix
        );

        return { maskedValue, value, customProps };
    },

    /**
     * Component lifecycle function.
     * Invoked once before the component is mounted. The return value will be used as the initial value of this.state
     *
     * @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
     * @see https://facebook.github.io/react/docs/component-specs.html#getinitialstate
     */
    getInitialState() {
        return this.prepareProps(this.props);
    },

    /**
     * Component lifecycle function.
     * Invoked when a component is receiving new props. This method is not called for the initial render.
     *
     * @param nextProps
     * @see https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
     */
    componentWillReceiveProps(nextProps) {
        this.setState(this.prepareProps(nextProps));
    },

    /**
     * Exposes the current masked value.
     *
     * @returns {String}
     */
    getMaskedValue() {
        return this.state.maskedValue;
    },

    /**
     * onChange Event Handler
     * @param event
     */
    handleChange(event) {
        event.preventDefault();
        let { maskedValue, value } = mask(
            event.target.value,
            this.props.precision,
            this.props.decimalSeparator,
            this.props.thousandSeparator,
            this.props.allowNegative,
            this.props.prefix,
            this.props.suffix
        );
        this.setState({ maskedValue, value });
        this.props.onChange(maskedValue, value, event);
    },

    /**
     * onFocus Event Handler
     * @param event
     */
    handleFocus(event) {
        //Whenever we receive focus check to see if the position is before the suffix, if not, move it.

        // if there is no suffix, then no worries just return
        if ( this.props.suffix.length == 0 ) {
            console.log("No suffix.");
            return;
        }
        let selection = this.getInputSelection(event.target);
        console.log(selection);

    },

    handleBlur(event) {

    },

    getInputSelection(el) {
        var start = 0, end = 0;
        if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
            start = el.selectionStart;
            end = el.selectionEnd;
        } else {
            //TODO Support for IE8 and below (maybe).

        }
        return {
            start: start,
            end: end
        };
    },

    /**
     * Component lifecycle function.
     * @returns {XML}
     * @see https://facebook.github.io/react/docs/component-specs.html#render
     */
    render() {
        return (
            <input
                type={this.props.inputType}
                value={this.state.maskedValue}
                onChange={this.handleChange}
                onFocus={this.handleFocus}
                onBlur={this.handleBlur}
                {...this.state.customProps}
            />
        )
    }
});

export default CurrencyInput
<commit_msg>testing<commit_after>import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import mask from './mask.js'

const CurrencyInput = React.createClass({

    /**
     * Prop validation.
     * @see https://facebook.github.io/react/docs/component-specs.html#proptypes
     */
    propTypes: {
        onChange: PropTypes.func,
        value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        decimalSeparator: PropTypes.string,
        thousandSeparator: PropTypes.string,
        precision: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
        inputType: PropTypes.string,
        allowNegative: PropTypes.bool,
        allowEmpty: PropTypes.bool,
        prefix: PropTypes.string,
        suffix: PropTypes.string
    },

    /**
     * Component lifecycle function.
     *
     * Invoked once and cached when the class is created. Values in the mapping will be set on this.props if that
     * prop is not specified by the parent component
     *
     * @see https://facebook.github.io/react/docs/component-specs.html#getdefaultprops
     */
    getDefaultProps() {
        return {
            onChange: function(maskValue, value, event) {/*no-op*/},
            value: '0',
            decimalSeparator: '.',
            thousandSeparator: ',',
            precision: '2',
            inputType: 'text',
            allowNegative: false,
            prefix: '',
            suffix: ''
        }
    },

    /**
     * General function used to cleanup and define the final props used for rendering
     * @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
     */
    prepareProps(props) {
        let customProps = {...props}; // babeljs converts to Object.assign, then polyfills.
        delete customProps.onChange;
        delete customProps.value;
        delete customProps.decimalSeparator;
        delete customProps.thousandSeparator;
        delete customProps.precision;
        delete customProps.inputType;
        delete customProps.allowNegative;
        delete customProps.allowEmpty;
        delete customProps.prefix;
        delete customProps.suffix;

        let initialValue = props.value;
        if (!initialValue) {
            initialValue = props.allowEmpty? null : '';
        }else{

            if (typeof initialValue == 'string') {
                // Some people, when confronted with a problem, think "I know, I'll use regular expressions."
                // Now they have two problems.

                // Strip out thousand separators, prefix, and suffix, etc.
                if (props.thousandSeparator === "."){
                    // special handle the . thousand separator
                    initialValue = initialValue.replace(/\./g, '');
                }

                if (props.decimalSeparator != "."){
                    // fix the decimal separator
                    initialValue = initialValue.replace(new RegExp(props.decimalSeparator, 'g'), '.');
                }

                //Strip out anything that is not a digit, -, or decimal separator
                initialValue = initialValue.replace(/[^0-9-.]/g, '');

                // now we can parse.
                initialValue = Number.parseFloat(initialValue);
            }
            initialValue = Number(initialValue).toLocaleString(undefined, {
                style                : 'decimal',
                minimumFractionDigits: props.precision,
                maximumFractionDigits: props.precision
            })

        }

        const { maskedValue, value } = mask(
            initialValue,
            props.precision,
            props.decimalSeparator,
            props.thousandSeparator,
            props.allowNegative,
            props.prefix,
            props.suffix
        );

        return { maskedValue, value, customProps };
    },

    /**
     * Component lifecycle function.
     * Invoked once before the component is mounted. The return value will be used as the initial value of this.state
     *
     * @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
     * @see https://facebook.github.io/react/docs/component-specs.html#getinitialstate
     */
    getInitialState() {
        return this.prepareProps(this.props);
    },

    /**
     * Component lifecycle function.
     * Invoked when a component is receiving new props. This method is not called for the initial render.
     *
     * @param nextProps
     * @see https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
     */
    componentWillReceiveProps(nextProps) {
        this.setState(this.prepareProps(nextProps));
    },

    /**
     * Exposes the current masked value.
     *
     * @returns {String}
     */
    getMaskedValue() {
        return this.state.maskedValue;
    },

    /**
     * onChange Event Handler
     * @param event
     */
    handleChange(event) {
        event.preventDefault();
        let { maskedValue, value } = mask(
            event.target.value,
            this.props.precision,
            this.props.decimalSeparator,
            this.props.thousandSeparator,
            this.props.allowNegative,
            this.props.prefix,
            this.props.suffix
        );
        this.setState({ maskedValue, value });
        this.props.onChange(maskedValue, value, event);
    },

    /**
     * onFocus Event Handler
     * @param event
     */
    handleFocus(event) {
        //Whenever we receive focus check to see if the position is before the suffix, if not, move it.

        // if there is no suffix, then no worries just return
        if ( this.props.suffix.length == 0 ) {
            console.log("No suffix.");
            return;
        }
        let selection = this.getInputSelection(ReactDOM.findDOMNode(event.target));
        console.log(selection);

    },

    handleBlur(event) {

    },

    getInputSelection(el) {
        var start = 0, end = 0;
        if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
            start = el.selectionStart;
            end = el.selectionEnd;
        } else {
            //TODO Support for IE8 and below (maybe).

        }
        return {
            start: start,
            end: end
        };
    },

    /**
     * Component lifecycle function.
     * @returns {XML}
     * @see https://facebook.github.io/react/docs/component-specs.html#render
     */
    render() {
        return (
            <input
                type={this.props.inputType}
                value={this.state.maskedValue}
                onChange={this.handleChange}
                onFocus={this.handleFocus}
                onBlur={this.handleBlur}
                {...this.state.customProps}
            />
        )
    }
});

export default CurrencyInput
<|endoftext|>


<commit_before>"use strict";

module.exports = function (grunt) {

	// A temporary directory used by amdserialize to output the processed modules.
	var tmpdir = "tmp/";

	// The final output directory.
	var outdir = "build/";

	// The grunt.config property populated by amdserialize, containing the
	// list of files to include in the layer.
	var outprop = "amdoutput";

	// The requirejs baseUrl.
	var baseUrl = "./";

	// Deployment directory.
	var deploydir = "deploy/";

	grunt.initConfig({
		// The loader config should go here.
		amdloader: {
			baseUrl: baseUrl,

			// Enable build of requirejs-text/text
			inlineText: true,

			// Here goes the config for the amd plugins build process (has, i18n, ecma402...).
			config: {}
		},

		// The common build config
		amdbuild: {
			// dir is the output directory.
			dir: tmpdir,

			// List of plugins that the build should not try to resolve at build time.
			runtimePlugins: [],

			// List of layers to build.
			layers: [{
				name: "layerName",
				include: [
					// Modules and layers listed here, and their dependencies, will be added to the layer.
				],
				includeShallow: [
					// Only the modules listed here (ie. NOT their dependencies) will be added to the layer.
				],
				exclude: [
					// Modules and layers listed here, and their dependencies, will NOT be in the layer.
				],
				excludeShallow: [
					// Only the modules listed here (ie. NOT their dependencies)  will NOT be in the layer.
				]
			}]
		},

		// Config to allow uglify to generate the layer.
		uglify: {
			options: {
				banner: "<%= " + outprop + ".header%>",
				sourceMap: true
			},
			dist: {
				src: "<%= " + outprop + ".modules.abs %>",
				dest: outdir + "<%= " + outprop + ".layerPath %>"
			}
		},

		// Copy the plugin files to the real output directory.
		copy: {
			plugins: {
				expand: true,
				cwd: tmpdir,
				src: "<%= " + outprop + ".plugins.rel %>",
				dest: outdir,
				dot: true
			},
			deploy: {
				expand: true,
				cwd: outdir + baseUrl,
				src: "*/*",
				dest: deploydir,
				dot: true
			}
		},

		// Erase previous build.
		clean: {
			erase: [outdir]
		}
	});

	// The main build task.
	grunt.registerTask("amdbuild", function (amdloader) {
		var name = this.name,
			layers = grunt.config(name).layers;

		layers.forEach(function (layer) {
			grunt.task.run("amddepsscan:" + layer.name + ":" + name + ":" + amdloader);
			grunt.task.run("amdserialize:" + layer.name + ":" + name + ":" + outprop);
			grunt.task.run("uglify");
			grunt.task.run("copy:plugins");
		});
	});

	// Load the plugin that provides the "amd" task.
	grunt.loadNpmTasks("grunt-amd-build");

	// Load vendor plugins.
	grunt.loadNpmTasks("grunt-contrib-uglify");
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-clean');

	// Default task.
	grunt.registerTask("build", ["clean:erase", "amdbuild:amdloader", "amdreportjson:amdbuild"]);
	grunt.registerTask("deploy", ["copy:deploy"]);
};
<commit_msg>remove deploy task from sample as it is not of great value and clutter the sample.<commit_after>"use strict";

module.exports = function (grunt) {

	// A temporary directory used by amdserialize to output the processed modules.
	var tmpdir = "tmp/";

	// The final output directory.
	var outdir = "build/";

	// The grunt.config property populated by amdserialize, containing the
	// list of files to include in the layer.
	var outprop = "amdoutput";

	grunt.initConfig({
		// The loader config should go here.
		amdloader: {
			// Everything should be relative to baseUrl
			baseUrl: "./",

			// Enable build of requirejs-text/text
			inlineText: true,

			// Here goes the config for the amd plugins build process (has, i18n, ecma402...).
			config: {}
		},

		// The common build config
		amdbuild: {
			// dir is the output directory.
			dir: tmpdir,

			// List of plugins that the build should not try to resolve at build time.
			runtimePlugins: [],

			// List of layers to build.
			layers: [{
				name: "layerName",
				include: [
					// Modules and layers listed here, and their dependencies, will be added to the layer.
				],
				includeShallow: [
					// Only the modules listed here (ie. NOT their dependencies) will be added to the layer.
				],
				exclude: [
					// Modules and layers listed here, and their dependencies, will NOT be in the layer.
				],
				excludeShallow: [
					// Only the modules listed here (ie. NOT their dependencies)  will NOT be in the layer.
				]
			}]
		},

		// Config to allow uglify to generate the layer.
		uglify: {
			options: {
				banner: "<%= " + outprop + ".header%>",
				sourceMap: true
			},
			dist: {
				src: "<%= " + outprop + ".modules.abs %>",
				dest: outdir + "<%= " + outprop + ".layerPath %>"
			}
		},

		// Copy the plugin files to the real output directory.
		copy: {
			plugins: {
				expand: true,
				cwd: tmpdir,
				src: "<%= " + outprop + ".plugins.rel %>",
				dest: outdir,
				dot: true
			}
		},

		// Erase previous build.
		clean: {
			erase: [outdir]
		}
	});

	// The main build task.
	grunt.registerTask("amdbuild", function (amdloader) {
		var name = this.name,
			layers = grunt.config(name).layers;

		layers.forEach(function (layer) {
			grunt.task.run("amddepsscan:" + layer.name + ":" + name + ":" + amdloader);
			grunt.task.run("amdserialize:" + layer.name + ":" + name + ":" + outprop);
			grunt.task.run("uglify");
			grunt.task.run("copy:plugins");
		});
	});

	// Load the plugin that provides the "amd" task.
	grunt.loadNpmTasks("grunt-amd-build");

	// Load vendor plugins.
	grunt.loadNpmTasks("grunt-contrib-uglify");
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-clean');

	// Default task.
	grunt.registerTask("build", ["clean:erase", "amdbuild:amdloader", "amdreportjson:amdbuild"]);
};
<|endoftext|>


<commit_before>import MemoryBackend from './backend/memory';
import BPlusTree from 'async-btree/lib/bplustree';
import createComparator from './util/comparator';

export default class Index {
  constructor(backend = new MemoryBackend(), config = {}) {
    // TODO Set the size to bigger value - this is only for testing.
    const { key = 'id', size = 2 } = config;
    this.backend = backend;
    this.config = { key, size };
    this.manifest = undefined;
    // Load manifest information..
    this.manifestPromise = backend.getManifest()
      .then(manifest => {
        // If the manifest is missing, provide initialization data.
        this.manifest = manifest || {
          populated: false,
          indexes: [],
        };
        this.btrees = this.manifest.indexes.map(this._createIndex.bind(this));
        return manifest;
      });
    this.btrees = [];
    // TODO Manage each indexes
    // TODO Query builder
    // TODO Data manager
    // TODO Syncing
  }
  getManifest() {
    if (this.manifest !== undefined) return Promise.resolve(manifest);
    return this.manifestPromise;
  }
  _createIndex(index) {
    // Create the index object - an actual B+Tree object, along with its
    // comparator code.
    let btree = new BPlusTree(
      null, // TODO
      this.config.size,
      createComparator(index),
    );
    return btree;
  }
  // Index manangement functions
  addIndexes(indexes) {

  }
  addIndex(index) {

  }
  removeIndex(index) {

  }
  // Data management functions
  add(document) {

  }
  remove(document) {

  }
  get(pk) {

  }
  commit() {

  }
  // Queries
  explain(query) {

  }
  search(query) {

  }
}
<commit_msg>Add getting manifest in each async function<commit_after>import MemoryBackend from './backend/memory';
import BPlusTree from 'async-btree/lib/bplustree';
import createComparator from './util/comparator';

export default class Index {
  constructor(backend = new MemoryBackend(), config = {}) {
    // TODO Set the size to bigger value - this is only for testing.
    const { key = 'id', size = 2 } = config;
    this.backend = backend;
    this.config = { key, size };
    this.manifest = undefined;
    // Load manifest information..
    this.manifestPromise = backend.getManifest()
      .then(manifest => {
        // If the manifest is missing, provide initialization data.
        this.manifest = manifest || {
          populated: false,
          indexes: [],
        };
        this.btrees = this.manifest.indexes.map(this._createIndex.bind(this));
        return manifest;
      });
    this.btrees = [];
    // TODO Manage each indexes
    // TODO Query builder
    // TODO Data manager
    // TODO Syncing
  }
  getManifest() {
    if (this.manifest !== undefined) return Promise.resolve(manifest);
    return this.manifestPromise;
  }
  _createIndex(index) {
    // Create the index object - an actual B+Tree object, along with its
    // comparator code.
    // Note that the B+Tree implementation treats keys and values separately -
    // the backend is responsible for synchronizing keys and values, since it
    // can simply copy / paste while loading. 'primary' index should be treated
    // differently, though.
    let btree = new BPlusTree(
      null, // TODO
      this.config.size,
      createComparator(index),
    );
    return btree;
  }
  // Index manangement functions
  addIndexes(indexes) {
    // Since each index doesn't touch other indexes at all, we can run this
    // in parallel - but manifest modifying should be an atomic operation in
    // order to do that.
  }
  async addIndex(index) {
    await this.getManifest();
  }
  async removeIndex(index) {
    await this.getManifest();
  }
  // Data management functions
  async add(document) {
    await this.getManifest();
  }
  async remove(document) {
    await this.getManifest();
  }
  async get(pk) {
    await this.getManifest();
  }
  async commit() {
    // If manifest doesn't exist, it can be ignored since nothing is written or
    // read.
    if (this.manifest === undefined) return;
  }
  // Queries
  async explain(query) {
    await this.getManifest();
  }
  async search(query) {
    await this.getManifest();
  }
}
<|endoftext|>


<commit_before>const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;

export function parse (source, name = '@') {
  if (!wasm)
    return init.then(() => parse(source));

  const len = source.length + 1;

  // need 2 bytes per code point plus analysis space so we double again
  const extraMem = (wasm.__heap_base.value || wasm.__heap_base) + len * 4 - wasm.memory.buffer.byteLength;
  if (extraMem > 0)
    wasm.memory.grow(Math.ceil(extraMem / 65536));

  const addr = wasm.sa(len - 1);
  (isLE ? copyLE : copyBE)(source, new Uint16Array(wasm.memory.buffer, addr, len));

  if (!wasm.parse())
    throw Object.assign(new Error(`Parse error ${name}:${source.slice(0, wasm.e()).split('\n').length}:${wasm.e() - source.lastIndexOf('\n', wasm.e() - 1)}`), { idx: wasm.e() });

  const imports = [], exports = [];
  while (wasm.ri()) imports.push({ s: wasm.is(), e: wasm.ie(),  ss: wasm.ss(), se: wasm.se(), d: wasm.id() });
  while (wasm.re()) exports.push(source.slice(wasm.es(), wasm.ee()));

  return [imports, exports, !!wasm.f()];
}

function copyBE (src, outBuf16) {
  const len = src.length;
  let i = 0;
  while (i < len) {
    const ch = src.charCodeAt(i);
    outBuf16[i++] = (ch & 0xff) << 8 | ch >>> 8;
  }
}

function copyLE (src, outBuf16) {
  const len = src.length;
  let i = 0;
  while (i < len)
    outBuf16[i] = src.charCodeAt(i++);
}

let wasm;

export const init = WebAssembly.compile(
  (binary => typeof atob === 'function' ? Uint8Array.from(atob(binary), x => x.charCodeAt(0)) : Buffer.from(binary, 'base64'))
  ('WASM_BINARY')
)
.then(WebAssembly.instantiate)
.then(({ exports }) => { wasm = exports; });
<commit_msg>only use atob in browser (#58)<commit_after>const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;

export function parse (source, name = '@') {
  if (!wasm)
    return init.then(() => parse(source));

  const len = source.length + 1;

  // need 2 bytes per code point plus analysis space so we double again
  const extraMem = (wasm.__heap_base.value || wasm.__heap_base) + len * 4 - wasm.memory.buffer.byteLength;
  if (extraMem > 0)
    wasm.memory.grow(Math.ceil(extraMem / 65536));

  const addr = wasm.sa(len - 1);
  (isLE ? copyLE : copyBE)(source, new Uint16Array(wasm.memory.buffer, addr, len));

  if (!wasm.parse())
    throw Object.assign(new Error(`Parse error ${name}:${source.slice(0, wasm.e()).split('\n').length}:${wasm.e() - source.lastIndexOf('\n', wasm.e() - 1)}`), { idx: wasm.e() });

  const imports = [], exports = [];
  while (wasm.ri()) imports.push({ s: wasm.is(), e: wasm.ie(),  ss: wasm.ss(), se: wasm.se(), d: wasm.id() });
  while (wasm.re()) exports.push(source.slice(wasm.es(), wasm.ee()));

  return [imports, exports, !!wasm.f()];
}

function copyBE (src, outBuf16) {
  const len = src.length;
  let i = 0;
  while (i < len) {
    const ch = src.charCodeAt(i);
    outBuf16[i++] = (ch & 0xff) << 8 | ch >>> 8;
  }
}

function copyLE (src, outBuf16) {
  const len = src.length;
  let i = 0;
  while (i < len)
    outBuf16[i] = src.charCodeAt(i++);
}

let wasm;

export const init = WebAssembly.compile(
  (binary => typeof window !== 'undefined' && typeof atob === 'function' ? Uint8Array.from(atob(binary), x => x.charCodeAt(0)) : Buffer.from(binary, 'base64'))
  ('WASM_BINARY')
)
.then(WebAssembly.instantiate)
.then(({ exports }) => { wasm = exports; });
<|endoftext|>


<commit_before>define('app/views/key', [
    'text!app/templates/key.html',
    'ember'
    ],
    /**
     *
     * Key page
     *
     * @returns Class
     */
    function(key_html) {
        return Ember.View.extend({
            tagName: false,
            keyBinding: 'Mist.key',

            disabledAssociateClass: function() {
                var count = 0
                Mist.backendsController.content.forEach(function(item){
                    count = count + item.machines.content.length;
                });
                if (count == 0) {
                    return 'ui-disabled';
                } else {
                    return '';
                }
            }.property('key'),

            keyMachines: function() {
                var key = this.key;
                machineNames = [];
                if (key) {
                    key.machines.forEach(function(item){
                        Mist.backendsController.content.forEach(function(backend){
                            backend.machines.content.forEach(function(machine){
                                if (machine.id == item[1]) {
                                    machineNames.push(machine);
                                }
                            });
                        });
                    });
                }
                console.log(machineNames);
                return machineNames;
            }.property('key.machines'),

            associateKey: function() {
                $.mobile.changePage('#key-associate-dialog');
                //check boxes for machines associated with this key
                $('li').find("input[type='checkbox']").attr("checked",false).checkboxradio("refresh");
                Mist.key.machines.forEach(function(item){
                    info(item[1]);
                    $('li.'+item[1]).find("input[type='checkbox']").attr("checked",true).checkboxradio("refresh");
                    Mist.backendsController.content.forEach(function(backend){
                        backend.machines.content.forEach(function(machine){
                            if (machine.id == item[1]) {
                                machine.set("selected",true);
                            }
                        });
                    });
                });
            },

            deleteKey: function() {
                var key = this.key;
                if (key.machines) {
                    machineNames = [];
                    key.machines.forEach(function(item){
                        Mist.backendsController.content.forEach(function(backend){
                            if (backend.id == item[0]) {
                                backend.machines.content.forEach(function(machine){
                                    if (machine.id == item[1]) {
                                        machineNames.push(machine.name);
                                    }
                                });
                            }
                        });
                    });
                }

                Mist.confirmationController.set('title', 'Delete Key: ' + key.name);
                if (key.machines.length > 0) {
                Mist.confirmationController.set('text', 'Your key is associated with ' + machineNames.toString() +'. Are you sure you want to delete ' +  key.name + '? You will not be able use console and monitoring on these VMs.');
                } else {
                    Mist.confirmationController.set('text', 'Are you sure you want to delete ' +
                                                key.name + '?');
                }
                Mist.confirmationController.set('callback', function() {
                    key.deleteKey();
                    key.machines.forEach(function(item){
                        Mist.backendsController.content.forEach(function(backend){
                            if (backend.id == item[0]) {
                                backend.machines.content.forEach(function(machine){
                                    if (machine.id == item[1]) {
                                        machine.set("hasKey", false);
                                    }
                                });
                            }
                        });
                    });
                    $.mobile.changePage('#keys');
                });
                Mist.confirmationController.set('fromDialog', true);

                Mist.confirmationController.show();
            },

            displayPrivate: function(){
                var key = this.key;
                Mist.keysController.getPrivKey(key.name);
                $.mobile.changePage('#key-private-dialog');
            },

            init: function() {
                this._super();
                // cannot have template in home.pt as pt complains
                this.set('template', Ember.Handlebars.compile(key_html));
                $('.public-key input').live('click', function(){
                    this.select();
                });
                $('.public-key input').live('change', function(){
                   return false;
                });
            },
        });
    }
);
<commit_msg>Fix a bug on association being deactivated when creating your first machine<commit_after>define('app/views/key', [
    'text!app/templates/key.html',
    'ember'
    ],
    /**
     *
     * Key page
     *
     * @returns Class
     */
    function(key_html) {
        return Ember.View.extend({
            tagName: false,
            keyBinding: 'Mist.key',

            disabledAssociateClass: function() {
                var count = 0
                Mist.backendsController.content.forEach(function(item){
                    count = count + item.machines.content.length;
                });
                if (count == 0) {
                    return 'ui-disabled';
                } else {
                    return '';
                }
            }.property('Mist.backendsController.machineCount'),

            keyMachines: function() {
                var key = this.key;
                machineNames = [];
                if (key) {
                    key.machines.forEach(function(item){
                        Mist.backendsController.content.forEach(function(backend){
                            backend.machines.content.forEach(function(machine){
                                if (machine.id == item[1]) {
                                    machineNames.push(machine);
                                }
                            });
                        });
                    });
                }
                console.log(machineNames);
                return machineNames;
            }.property('key.machines'),

            associateKey: function() {
                $.mobile.changePage('#key-associate-dialog');
                //check boxes for machines associated with this key
                $('li').find("input[type='checkbox']").attr("checked",false).checkboxradio("refresh");
                Mist.key.machines.forEach(function(item){
                    info(item[1]);
                    $('li.'+item[1]).find("input[type='checkbox']").attr("checked",true).checkboxradio("refresh");
                    Mist.backendsController.content.forEach(function(backend){
                        backend.machines.content.forEach(function(machine){
                            if (machine.id == item[1]) {
                                machine.set("selected",true);
                            }
                        });
                    });
                });
            },

            deleteKey: function() {
                var key = this.key;
                if (key.machines) {
                    machineNames = [];
                    key.machines.forEach(function(item){
                        Mist.backendsController.content.forEach(function(backend){
                            if (backend.id == item[0]) {
                                backend.machines.content.forEach(function(machine){
                                    if (machine.id == item[1]) {
                                        machineNames.push(machine.name);
                                    }
                                });
                            }
                        });
                    });
                }

                Mist.confirmationController.set('title', 'Delete Key: ' + key.name);
                if (key.machines.length > 0) {
                Mist.confirmationController.set('text', 'Your key is associated with ' + machineNames.toString() +'. Are you sure you want to delete ' +  key.name + '? You will not be able use console and monitoring on these VMs.');
                } else {
                    Mist.confirmationController.set('text', 'Are you sure you want to delete ' +
                                                key.name + '?');
                }
                Mist.confirmationController.set('callback', function() {
                    key.deleteKey();
                    key.machines.forEach(function(item){
                        Mist.backendsController.content.forEach(function(backend){
                            if (backend.id == item[0]) {
                                backend.machines.content.forEach(function(machine){
                                    if (machine.id == item[1]) {
                                        machine.set("hasKey", false);
                                    }
                                });
                            }
                        });
                    });
                    $.mobile.changePage('#keys');
                });
                Mist.confirmationController.set('fromDialog', true);

                Mist.confirmationController.show();
            },

            displayPrivate: function(){
                var key = this.key;
                Mist.keysController.getPrivKey(key.name);
                $.mobile.changePage('#key-private-dialog');
            },

            init: function() {
                this._super();
                // cannot have template in home.pt as pt complains
                this.set('template', Ember.Handlebars.compile(key_html));
                $('.public-key input').live('click', function(){
                    this.select();
                });
                $('.public-key input').live('change', function(){
                   return false;
                });
            },
        });
    }
);
<|endoftext|>


<commit_before>// potato level for PC, higher = faster :-)
// TODO: remove in production
potato = 4;
c.width = 1920 / potato;
c.height = 1080 / potato;

// accumulators
bAcc = 0;
fAcc = 0;

r = t => {
  requestAnimationFrame(r, c);

  // run fft
  analyser.getByteFrequencyData(analyserArray);

  // set the "a" time variable
  g.uniform1f(g.getUniformLocation(P, 'a'), soundbox.audioCtx.currentTime);

  // set the "b" resolution variable
  g.uniform2f(g.getUniformLocation(P, 'b'), g.canvas.width, g.canvas.height);

  // set the "c" bass volume variable
  g.uniform1f(g.getUniformLocation(P, 'c'), analyserArray[11] / 255);
  // set the "d" treble volume variable
  g.uniform1f(g.getUniformLocation(P, 'd'), analyserArray[222] / 255);
  // accumulated bass
  g.uniform1f(g.getUniformLocation(P, 'e'), bAcc += analyserArray[11] / 1024);
  // frequency of lead synth
  g.uniform1f(g.getUniformLocation(P, 'f'), fAcc = 0.9 * fAcc + 0.1 * s.tracks[5][0].osc1.frequency.value);

  g.drawArrays(6,0,3); // g.TRIANGLE_FAN = 6
}

// music
s = new soundbox.MusicGenerator();
s.connect(soundbox.audioCtx.destination);
analyser = soundbox.audioCtx.createAnalyser();
analyserArray = new Uint8Array(analyser.frequencyBinCount);

// connect kick drum track, first column to analyser
s.tracks[0][0].out.connect(analyser);

// connect hihat drum track, first column to analyser
s.tracks[2][0].out.connect(analyser);

// onload
g = c.getContext('webgl');

P = g.createProgram();

// vertex shader
g.shaderSource(S=g.createShader(35633), require('./vertex.glsl')); // g.VERTEX_SHADER = 35633
g.compileShader(S);g.attachShader(P,S);

// fragment shader
g.shaderSource(S=g.createShader(35632), require('./fragment.glsl')); // g.FRAGMENT_SHADER = 35632
g.compileShader(S);g.attachShader(P,S);

// Check for any compilation error
// TODO: remove in production
if (!g.getShaderParameter(S, 35713)) { // g.COMPILE_STATUS = 35713
    alert(g.getShaderInfoLog(S));
}

g.linkProgram(P);
g.useProgram(P);

// g.ARRAY_BUFFER = 34962
g.bindBuffer(34962, g.createBuffer());
g.bufferData(34962, new Int8Array([-3,1,1,-3,1,1]),35044); // 35044 = gl.STATIC_DRAW
g.enableVertexAttribArray(0);
g.vertexAttribPointer(0,2,5120,0,0,0); // g.BYTE = 5120

// start rendering and music playback
r();
s.play(song);
<commit_msg>Attempt getting rid of fps dependency<commit_after>// potato level for PC, higher = faster :-)
// TODO: remove in production
potato = 4;
c.width = 1920 / potato;
c.height = 1080 / potato;

// time at previous frame
oldTime = 0;

// accumulators
bAcc = 0;
fAcc = 0;
bPeak = 0; // bass peak, max(bass, bPeak)

r = t => {
  requestAnimationFrame(r, c);

  d = (t - oldTime) / 16;

  bass = analyserArray[11] / 255;
  treble = analyserArray[222] / 255;
  bPeak = Math.max(0.95 * bPeak + 0.05 * bass * d, bass);

  // run fft
  analyser.getByteFrequencyData(analyserArray);

  // set the "a" time variable
  g.uniform1f(g.getUniformLocation(P, 'a'), soundbox.audioCtx.currentTime);

  // set the "b" resolution variable
  g.uniform2f(g.getUniformLocation(P, 'b'), g.canvas.width, g.canvas.height);

  // set the "c" bass volume variable
  g.uniform1f(g.getUniformLocation(P, 'c'), bPeak);
  // set the "d" treble volume variable
  g.uniform1f(g.getUniformLocation(P, 'd'), treble);
  // accumulated bass for bass synced blood cell movement
  g.uniform1f(g.getUniformLocation(P, 'e'), bAcc = 0.9 * bAcc + 0.1 * bPeak * d);
  // frequency of lead synth
  g.uniform1f(g.getUniformLocation(P, 'f'), fAcc = 0.9 * fAcc + 0.1 * s.tracks[5][0].osc1.frequency.value * d);

  g.drawArrays(6,0,3); // g.TRIANGLE_FAN = 6

  oldTime = t;
}

// music
s = new soundbox.MusicGenerator();
s.connect(soundbox.audioCtx.destination);
analyser = soundbox.audioCtx.createAnalyser();
analyserArray = new Uint8Array(analyser.frequencyBinCount);

// connect kick drum track, first column to analyser
s.tracks[0][0].out.connect(analyser);

// connect hihat drum track, first column to analyser
s.tracks[2][0].out.connect(analyser);

// onload
g = c.getContext('webgl');

P = g.createProgram();

// vertex shader
g.shaderSource(S=g.createShader(35633), require('./vertex.glsl')); // g.VERTEX_SHADER = 35633
g.compileShader(S);g.attachShader(P,S);

// fragment shader
g.shaderSource(S=g.createShader(35632), require('./fragment.glsl')); // g.FRAGMENT_SHADER = 35632
g.compileShader(S);g.attachShader(P,S);

// Check for any compilation error
// TODO: remove in production
if (!g.getShaderParameter(S, 35713)) { // g.COMPILE_STATUS = 35713
    alert(g.getShaderInfoLog(S));
}

g.linkProgram(P);
g.useProgram(P);

// g.ARRAY_BUFFER = 34962
g.bindBuffer(34962, g.createBuffer());
g.bufferData(34962, new Int8Array([-3,1,1,-3,1,1]),35044); // 35044 = gl.STATIC_DRAW
g.enableVertexAttribArray(0);
g.vertexAttribPointer(0,2,5120,0,0,0); // g.BYTE = 5120

// start rendering and music playback
r(0);
s.play(song);
<|endoftext|>


<commit_before>var unicode = require('unicode-categories');

// http://es5.github.com/#x7.6
// ECMAscript identifier starts with `$`, `_`,
// or letter from (Lu Ll Lt Lm Lo Nl) unicode groups.
// Then identifier can also be from groups (Nd, Mn, Mc, or Pc).
// Roy identifier cannot have letter u03BB (greek lowercase lambda)
// because it's used in anonymous functions.
var IDENTIFIER = new RegExp(
    unicode.ECMA.identifier.source.replace('\\u03BB', '')
);

var NUMBER = /^-?[0-9]+(\.[0-9]+)?([eE][\-\+]?[0-9]+)?/;
var STRING = /^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/;
var COMMENT = /^\/\/.*/;
var WHITESPACE = /^[^\n\S]+/;
var INDENT = /^(?:\n[^\n\S]*)+/;
var GENERIC = /^#([a-z]+)/;
var SHEBANG = /^#!.*/;

var chunk;
var indent;
var indents;
var tokens;
var lineno;

var identifierToken = function() {
    var value,
        name,
        token = IDENTIFIER.exec(chunk);
    if(token) {
        value = token[0];
        switch(value) {
        case 'true':
        case 'false':
            name = 'BOOLEAN';
            break;
        case 'Function':
        case 'let':
        case 'if':
        case 'instance':
        case 'then':
        case 'else':
        case 'data':
        case 'type':
        case 'typeclass':
        case 'match':
        case 'case':
        case 'do':
        case 'return':
        case 'with':
        case 'where':
            name = value.toUpperCase();
            break;
        default:
            name = 'IDENTIFIER';
            break;
        }
        tokens.push([name, value, lineno]);
        return token[0].length;
    }
    return 0;
};

var numberToken = function() {
    var token = NUMBER.exec(chunk);
    if(token) {
        tokens.push(['NUMBER', token[0], lineno]);
        return token[0].length;
    }
    return 0;
};

var stringToken = function() {
  var token = STRING.exec(chunk);
  if (token) {
    tokens.push(['STRING', token[0], lineno]);
    return token[0].length;

  }
  return 0;
};

var genericToken = function() {
    var token = GENERIC.exec(chunk);
    if(token) {
        tokens.push(['GENERIC', token[1], lineno]);
        return token[0].length;
    }
    return 0;
};

var commentToken = function() {
    var token = COMMENT.exec(chunk);
    if(token) {
        tokens.push(['COMMENT', token[0], lineno]);
        return token[0].length;
    }
    return 0;
};

var whitespaceToken = function() {
    var token = WHITESPACE.exec(chunk);
    if(token) {
        return token[0].length;
    }
    return 0;
};

// If an OUTDENT is followed by a line continuer,
// the next TERMINATOR token is supressed.
var lineContinuer = {
    "where": true
};

var lineToken = function() {
    var token = INDENT.exec(chunk);
    if(token) {
        var lastNewline = token[0].lastIndexOf("\n") + 1;
        var size = token[0].length - lastNewline;
        var terminated = false;
        if(size > indent) {
            indents.push(size);
            tokens.push(['INDENT', size - indent, lineno]);
        } else {
            if(size < indent) {
                var last = indents[indents.length - 1];
                while(size < last) {
                    tokens.push(['OUTDENT', last - size, lineno]);
                    indents.pop();
                    last = indents[indents.length - 1];
                }
            }
            if(tokens.length > 0) {
                var lookahead = IDENTIFIER.exec(chunk.slice(token[0].length));

                if (!lookahead || !lineContinuer[lookahead[0]]) {
                    tokens.push(['TERMINATOR', token[0].substring(0, lastNewline), lineno]);
                }
            }
        }
        indent = size;
        return token[0].length;
    }
    return 0;
};

var literalToken = function() {
    var tag = chunk.slice(0, 1);
    var next;
    switch(tag) {
    case '<':
        next = chunk.slice(0, 2);
        if(next == '<=') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        } else if(next == '<-') {
            tokens.push(['LEFTARROW', next, lineno]);
            return 2;
        } else if(next == '<<') {
            tokens.push(['MATH', next, lineno]);
            return 2;
        }
        tokens.push(['COMPARE', tag, lineno]);
        return 1;
    case '>':
        next = chunk.slice(0, 2);
        if(next == '>=') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        } else if(next == '>>') {
            tokens.push(['MATH', next, lineno]);
            return 2;
        }
        tokens.push(['COMPARE', tag, lineno]);
        return 1;
    case '=':
        next = chunk.slice(0, 2);
        if(next == '==') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '!':
        next = chunk.slice(0, 2);
        if(next == '!=') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '*':
    case '/':
    case '%':
        tokens.push(['MATH', tag, lineno]);
        return 1;
    case '[':
    case '|':
        next = chunk.slice(0, 2);
        if(next == '||') {
            tokens.push(['BOOLOP', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case ')':
        if(tokens[tokens.length-1][0] == 'TERMINATOR') {
            tokens.pop();
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '+':
        next = chunk.slice(0, 2);
        if(next == '++') {
            tokens.push(['CONCAT', tag, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '-':
        next = chunk.slice(0, 2);
        if (next == '->') {
            tokens.push(['RIGHTARROW', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '&':
        next = chunk.slice(0, 2);
        if(next == '&&') {
            tokens.push(['BOOLOP', next, lineno]);
            return 2;
        }
        return 0;
    case 'λ':
    case '\\':
        tokens.push(['LAMBDA', tag, lineno]);
        return 1;
    case '←':
        tokens.push(['LEFTARROW', tag, lineno]);
        return 1;
    case '→':
        tokens.push(['RIGHTARROW', tag, lineno]);
        return 1;
    case '⇒':
        tokens.push(['RIGHTFATARROW', tag, lineno]);
        return 1;
    case '@':
    case ']':
    case ':':
    case '.':
    case ',':
    case '{':
    case '}':
    case '(':
        tokens.push([tag, tag, lineno]);
        return 1;
    }
    return 0;
};

var shebangToken = function() {
    var token = SHEBANG.exec(chunk);
    if (token) {
        tokens.push(['SHEBANG', token[0], lineno]);
        return token[0].length;
    }
    return 0;
};

exports.tokenise = function(source) {
    /*jshint boss:true*/
    indent = 0;
    indents = [];
    tokens = [];
    lineno = 0;
    var i = 0;
    while(chunk = source.slice(i)) {
        var diff = identifierToken() || numberToken() || stringToken() || genericToken() || commentToken() || whitespaceToken() || lineToken() || literalToken() || shebangToken();
        if(!diff) {
            throw "Couldn't tokenise: " + chunk.substring(0, chunk.indexOf("\n") > -1 ? chunk.indexOf("\n") : chunk.length);
        }
        lineno += source.slice(i, i + diff).split('\n').length - 1;
        i += diff;
    }
    tokens.push(['EOF', '', lineno]);
    return tokens;
};
<commit_msg>Removed unused var.<commit_after>var unicode = require('unicode-categories');

// http://es5.github.com/#x7.6
// ECMAscript identifier starts with `$`, `_`,
// or letter from (Lu Ll Lt Lm Lo Nl) unicode groups.
// Then identifier can also be from groups (Nd, Mn, Mc, or Pc).
// Roy identifier cannot have letter u03BB (greek lowercase lambda)
// because it's used in anonymous functions.
var IDENTIFIER = new RegExp(
    unicode.ECMA.identifier.source.replace('\\u03BB', '')
);

var NUMBER = /^-?[0-9]+(\.[0-9]+)?([eE][\-\+]?[0-9]+)?/;
var STRING = /^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/;
var COMMENT = /^\/\/.*/;
var WHITESPACE = /^[^\n\S]+/;
var INDENT = /^(?:\n[^\n\S]*)+/;
var GENERIC = /^#([a-z]+)/;
var SHEBANG = /^#!.*/;

var chunk;
var indent;
var indents;
var tokens;
var lineno;

var identifierToken = function() {
    var value,
        name,
        token = IDENTIFIER.exec(chunk);
    if(token) {
        value = token[0];
        switch(value) {
        case 'true':
        case 'false':
            name = 'BOOLEAN';
            break;
        case 'Function':
        case 'let':
        case 'if':
        case 'instance':
        case 'then':
        case 'else':
        case 'data':
        case 'type':
        case 'typeclass':
        case 'match':
        case 'case':
        case 'do':
        case 'return':
        case 'with':
        case 'where':
            name = value.toUpperCase();
            break;
        default:
            name = 'IDENTIFIER';
            break;
        }
        tokens.push([name, value, lineno]);
        return token[0].length;
    }
    return 0;
};

var numberToken = function() {
    var token = NUMBER.exec(chunk);
    if(token) {
        tokens.push(['NUMBER', token[0], lineno]);
        return token[0].length;
    }
    return 0;
};

var stringToken = function() {
  var token = STRING.exec(chunk);
  if (token) {
    tokens.push(['STRING', token[0], lineno]);
    return token[0].length;

  }
  return 0;
};

var genericToken = function() {
    var token = GENERIC.exec(chunk);
    if(token) {
        tokens.push(['GENERIC', token[1], lineno]);
        return token[0].length;
    }
    return 0;
};

var commentToken = function() {
    var token = COMMENT.exec(chunk);
    if(token) {
        tokens.push(['COMMENT', token[0], lineno]);
        return token[0].length;
    }
    return 0;
};

var whitespaceToken = function() {
    var token = WHITESPACE.exec(chunk);
    if(token) {
        return token[0].length;
    }
    return 0;
};

// If an OUTDENT is followed by a line continuer,
// the next TERMINATOR token is supressed.
var lineContinuer = {
    "where": true
};

var lineToken = function() {
    var token = INDENT.exec(chunk);
    if(token) {
        var lastNewline = token[0].lastIndexOf("\n") + 1;
        var size = token[0].length - lastNewline;
        if(size > indent) {
            indents.push(size);
            tokens.push(['INDENT', size - indent, lineno]);
        } else {
            if(size < indent) {
                var last = indents[indents.length - 1];
                while(size < last) {
                    tokens.push(['OUTDENT', last - size, lineno]);
                    indents.pop();
                    last = indents[indents.length - 1];
                }
            }
            if(tokens.length > 0) {
                var lookahead = IDENTIFIER.exec(chunk.slice(token[0].length));

                if (!lookahead || !lineContinuer[lookahead[0]]) {
                    tokens.push(['TERMINATOR', token[0].substring(0, lastNewline), lineno]);
                }
            }
        }
        indent = size;
        return token[0].length;
    }
    return 0;
};

var literalToken = function() {
    var tag = chunk.slice(0, 1);
    var next;
    switch(tag) {
    case '<':
        next = chunk.slice(0, 2);
        if(next == '<=') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        } else if(next == '<-') {
            tokens.push(['LEFTARROW', next, lineno]);
            return 2;
        } else if(next == '<<') {
            tokens.push(['MATH', next, lineno]);
            return 2;
        }
        tokens.push(['COMPARE', tag, lineno]);
        return 1;
    case '>':
        next = chunk.slice(0, 2);
        if(next == '>=') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        } else if(next == '>>') {
            tokens.push(['MATH', next, lineno]);
            return 2;
        }
        tokens.push(['COMPARE', tag, lineno]);
        return 1;
    case '=':
        next = chunk.slice(0, 2);
        if(next == '==') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '!':
        next = chunk.slice(0, 2);
        if(next == '!=') {
            tokens.push(['COMPARE', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '*':
    case '/':
    case '%':
        tokens.push(['MATH', tag, lineno]);
        return 1;
    case '[':
    case '|':
        next = chunk.slice(0, 2);
        if(next == '||') {
            tokens.push(['BOOLOP', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case ')':
        if(tokens[tokens.length-1][0] == 'TERMINATOR') {
            tokens.pop();
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '+':
        next = chunk.slice(0, 2);
        if(next == '++') {
            tokens.push(['CONCAT', tag, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '-':
        next = chunk.slice(0, 2);
        if (next == '->') {
            tokens.push(['RIGHTARROW', next, lineno]);
            return 2;
        }
        tokens.push([tag, tag, lineno]);
        return 1;
    case '&':
        next = chunk.slice(0, 2);
        if(next == '&&') {
            tokens.push(['BOOLOP', next, lineno]);
            return 2;
        }
        return 0;
    case 'λ':
    case '\\':
        tokens.push(['LAMBDA', tag, lineno]);
        return 1;
    case '←':
        tokens.push(['LEFTARROW', tag, lineno]);
        return 1;
    case '→':
        tokens.push(['RIGHTARROW', tag, lineno]);
        return 1;
    case '⇒':
        tokens.push(['RIGHTFATARROW', tag, lineno]);
        return 1;
    case '@':
    case ']':
    case ':':
    case '.':
    case ',':
    case '{':
    case '}':
    case '(':
        tokens.push([tag, tag, lineno]);
        return 1;
    }
    return 0;
};

var shebangToken = function() {
    var token = SHEBANG.exec(chunk);
    if (token) {
        tokens.push(['SHEBANG', token[0], lineno]);
        return token[0].length;
    }
    return 0;
};

exports.tokenise = function(source) {
    /*jshint boss:true*/
    indent = 0;
    indents = [];
    tokens = [];
    lineno = 0;
    var i = 0;
    while(chunk = source.slice(i)) {
        var diff = identifierToken() || numberToken() || stringToken() || genericToken() || commentToken() || whitespaceToken() || lineToken() || literalToken() || shebangToken();
        if(!diff) {
            throw "Couldn't tokenise: " + chunk.substring(0, chunk.indexOf("\n") > -1 ? chunk.indexOf("\n") : chunk.length);
        }
        lineno += source.slice(i, i + diff).split('\n').length - 1;
        i += diff;
    }
    tokens.push(['EOF', '', lineno]);
    return tokens;
};
<|endoftext|>


<commit_before>/**
 * @package browserify-plugin-can-compile
 * @category javascript
 * @author scenecs <scenecs@t-online.de>
 */

'use strict';

import through2 from 'through2';
import canCompiler from 'can-compile';
import fs from 'fs';
import path from 'path';
import CanCompileScriptsCache from './library/CanCompileScriptsCache';
import es6Promise from 'es6-promise';

// Polyfill
es6Promise.polyfill();

/**
 * @property browserifyPluginCanCompileInstance
 * @private
 * @static
 * @type BrowserifyPluginCanCompile
 * @default undefined
 */
let browserifyPluginCanCompileInstance;

/**
 * Browserify Plugin: browserify-plugin-can-compile
 * =================================================
 *
 * A [Browserify](https://github.com/substack/node-browserify) plugin to require canJs template
 * files in a javascript file. The template will be precompiled with module "can-compile" and will
 * be bundled with the other javascript code. It is possible to save all required templates in an
 * external javascript file.
 *
 * b.plugin(BrowserifyPluginCanCompile.compile [, options])
 * ---------------------------------------------------------
 *
 * ### options
 *
 * The options object allows the following configuration options:
 *
 *    - `filename` {String}: The name of the file to be compiled
 *    - `version` {String}: The CanJS version to be used
 *    - `log` {Function}: A logger function (e..g `console.log.bind(console)`)
 *    - `normalizer` {Function}: A Function that returns the normalized path name
 *    - `tags` {Array}: A list of all your can.Component tags. They need to be registered in order to pre-compile views properly.
 *    - `extensions` {Object}: An object to map custom file extensions to the standard extension (e.g. `{ 'mst' : 'mustache' }`)
 *    - `viewAttributes` {Array}: A list of attribute names (RegExp or String), used for additional behavior for an attribute in a view (can.view.attr)
 *    - `paths` an object with `ejs`, `mustache` or `stache` and a `jquery` property pointing to files of existing versions or CanJS and jQuery instead of the CDN links.
 *
 * All options are optional. If the option `filename` is defined, the precompiled templates will be
 * saved in this external file.
 *
 * For more information please see at can-compile dokumentation: https://github.com/canjs/can-compile
 *
 * Example
 * --------
 *
 * ```javascript
 *  import browserify from 'browserify';
 *  import browserifyPluginCanCompile from 'browserify-plugin-can-compile';
 *
 *  let b = browserify();
 *
 *  b.add('./app.js')
 *   .plugin(browserifyPluginCanCompile, {
 *      "version": "2.3.23",
 *      "filename": "./views-app.js"
 *    })
 *   .bundle().pipe(process.stdout);
 * ```
 *
 * @class BrowserifyPluginCanCompile
 */
export class BrowserifyPluginCanCompile {
  /**
   *
   * @constructor
   * @param {Browserify} bundle Browserify instance
   * @see https://github.com/substack/node-browserify#browserifyfiles--opts
   * @param {Object} options Can-compile options to influence the compile process. This options will
   *    be piped to the module "can-compile".
   * @see https://github.com/canjs/can-compile#programmatically
   */
  constructor(bundle, options) {
    /**
     * @property buffer
     * @private
     * @type Array
     * @default []
     */
    this.buffer = [];

    /**
     * @property options
     * @private
     * @type Object
     * @default {
     *   "extensions": {
     *     "stache": "stache",
     *     "ejs": "ejs",
     *     "mustache": "mustache"
     *   }
     * }
     */
    this.options = {
      "extensions": {
        "stache": "stache",
        "ejs": "ejs",
        "mustache": "mustache"
      },
      "paths": undefined,
      "requirePaths": {
        'jquery': 'jquery',
        'can': 'can',
        'ejs': 'can/view/ejs/ejs',
        'stache': 'can/view/stache/stache',
        'mustache': 'can/view/mustache/mustache'
      },
      "filename": undefined,
      "version": undefined,
      "normalizer": undefined,
      "wrapper": 'module.exports = {{{content}}};',
      "wrapperForExternalTemplateFile": undefined,
      "cacheCanCompileScripts": true
    };

    /**
     * contains the passed browserify instance
     *
     * @property browserifyInstance
     * @type Browserify
     * @default undefined
     */
    this.browserifyInstance = undefined;

    /**
     * @property promise
     * @type Promise
     * @default Promise.resolve(this)
     */
    this.promise = Promise.resolve(this);

    if(!bundle || !bundle.pipeline) {
      throw new Error('The passed parameter "bundle" seems to be not a valid instance of "Browserify"!');
    }
    this.browserifyInstance = bundle;

    if(!options || !options.version) {
      throw new Error('Missing option "options.version"! Pass the currently used version of canJS.');
    }
    this.setOptions(options);

    if(this.constructor.isNone(this.options.normalizer)) {
      this.options.normalizer = this.getDefaultNormalizer();
    }

    if(this.constructor.isNone(this.options.paths) && true === this.options.cacheCanCompileScripts) {
      this.promise = new Promise((resolve, reject) => {
        let canCompileScriptsCache = CanCompileScriptsCache.createCache(this.options.version);

        /* istanbul ignore next */
        canCompileScriptsCache.on("finish", (files) => {
          this.setPaths(files);
          resolve(this);
        });

        /* istanbul ignore next */
        canCompileScriptsCache.on('error', (error) => {
          reject(error);
        });
      });
    }

    this.extendBrowserifyPipeline();
  }

  /**
   * @method setOptions
   * @private
   * @chainable
   * @param {Object} options
   * @return {BrowserifyPluginCanCompile}
   */
  setOptions(options) {
    if('object' !== typeof options || Array.isArray(options)) {
      throw new Error('The passed parameter "options" must be an object!');
    }

    Array.prototype.forEach.call(Object.keys(options), (key, index) => {
      this.options[key] = options[key];
    });

    return this;
  }

  /**
   * @method getOptions
   * @private
   * @return {Object} Returns the options.
   */
  getOptions() {
    return this.options;
  }

  /**
   * @method setPaths
   * @private
   * @chainable
   * @param {Array} paths
   * @return {BrowserifyPluginCanCompile}
   */
  setPaths(paths) {
    if(!Array.isArray(paths)) {
      throw new Error('The passed parameter "paths" must be an array!');
    }

    this.options.paths = paths;
    return this;
  }

  /**
   * @method getPaths
   * @private
   * @return {Array} Return an array of the path of the vendor scripts.
   */
  getPaths() {
    return this.options.paths;
  }

  /**
   * @method extendBrowserifyPipeline
   * @private
   */
  extendBrowserifyPipeline() {
    const instance = this.browserifyInstance;
    instance.transform(BrowserifyPluginCanCompile.transform);
  }

  /**
   * Creates a Regular Expressions for the defined template extensions.
   *
   * @method getFileExtensionRegExp
   * @private
   * @return {RegExp} Returns the generated Regular Expressions with capturing parentheses for
   *    filename and file extension
   */
  getFileExtensionRegExp() {
    const optionExtensions = this.options.extensions;

    if("object" !== typeof optionExtensions || Array.isArray(optionExtensions)) {
      throw new Error('Option "extensions" must be a key-value object!');
    }

    let flags = "ig";
    let fileExtensions = Object.keys(this.options.extensions).map(function(item, index){
      return item.replace(new RegExp("[^\\w-]", flags), "");
    });

    return new RegExp("^.*\\" + path.sep + "([\\w-]+)\\.(" + fileExtensions.join("|") + ")$", flags);
  }

  /**
   * The normalizer returns a normalized key for the parsed template. With this key is it possible
   *    to call the template in the application. By default, the key is the filename of the template.
   *
   * The normalizer can be overwritten via plugin configuration. For more information please see
   *    at can-compile dokumentation: https://github.com/canjs/can-compile
   *
   * @method getDefaultNormalizer
   * @private
   * @return {String} Returns the key for the rendered can template.
   *
   * @see https://github.com/canjs/can-compile#programmatically
   */
  getDefaultNormalizer() {
    let fileExtRegEx = this.getFileExtensionRegExp();

    return function normalizer(file){
      let filename;

      try {
        filename = (fileExtRegEx.exec(file))[1];
      } catch(err) {
        filename = file;
      }

      return filename;
    }
  }

  /**
   * @method addPlugin
   * @static
   * @param {Browserify} bundle Browserify instance
   * @see https://github.com/substack/node-browserify#browserifyfiles--opts
   * @param {Object} options Can-compile options to influence the compile process. This options will
   *    be piped to the module "can-compile".
   * @see https://github.com/canjs/can-compile#programmatically
   * @return {BrowserifyPluginCanCompile}
   */
  static addPlugin(bundle, options) {
    let instance;

    try {
      instance = BrowserifyPluginCanCompile.getInstance();
    } catch(error) {
      browserifyPluginCanCompileInstance = instance = new BrowserifyPluginCanCompile(bundle, options);
    }
    return instance;
  }

  /**
   * @method getInstance
   * @static
   * @return {BrowserifyPluginCanCompile} Returns the current instance
   */
  static getInstance() {
    if(!browserifyPluginCanCompileInstance) {
      throw new Error('No existing "BrowserifyPluginCanCompile" instance! Create a new instance with "browserifyPluginCanCompile.addPlugin(bundle, options)"');
    }

    return browserifyPluginCanCompileInstance;
  }

  /**
   * @method reset
   * @static
   */
  static reset() {
    browserifyPluginCanCompileInstance = undefined;
  }

  /**
   * @method transform
   * @static
   * @private
   * @param {String} file path of the current file
   * @return {BrowserifyPluginCanCompile}
   */
  static transform(file) {
    const instance = BrowserifyPluginCanCompile.getInstance();
    const fileExtRegEx = instance.getFileExtensionRegExp();

    if(!fileExtRegEx.test(file)) {
      return through2.obj();
    }

    return through2.obj(BrowserifyPluginCanCompile.transformFunction(file), BrowserifyPluginCanCompile.flushFunction());
  }

  /**
   * @method transformFunction
   * @private
   * @static
   * @param {String} file
   * @return {Function} Returns the transform function
   */
  static transformFunction(file) {
    const _file = file;

    return function transform(chunk, encoding, callback){
      let currentInstance = BrowserifyPluginCanCompile.getInstance();
      currentInstance.promise.then((instance) => {
        let options = instance.getOptions();
        let currentWrapper = options.wrapper;

        if(!BrowserifyPluginCanCompile.isNone(options.filename)) {
          currentWrapper = options.wrapperForExternalTemplateFile;
        }

        canCompiler(_file, options, (err, result) => {
          if(err) {
            return callback(err);
          }
          let bufferedResult = new Buffer(result, "utf8");

          if(BrowserifyPluginCanCompile.isNone(options.filename)){
            chunk = bufferedResult;
          } else {
            Array.prototype.push.call(instance.buffer, bufferedResult);
            chunk = new Buffer("module.export = can.view('" + options.normalizer(_file) + "');", "utf8");
          }

          this.push(chunk);
          callback();
        });
      }, (error) => {
        callback(error);
      });
    }
  }

  /**
   * @method flushFunction
   * @private
   * @static
   * @return {Function} Returns the flush function
   */
  static flushFunction() {

    return function flush(callback){
      let currentInstance = BrowserifyPluginCanCompile.getInstance();

      currentInstance.promise.then((instance) => {
        let options = instance.getOptions();

        if(!BrowserifyPluginCanCompile.isNone(options.filename)) {
          let writeStream;
          let file = path.normalize(options.filename);
          let filePath = path.dirname(file);

          mkdirp.sync(filePath);
          writeStream = fs.createWriteStream(file, { "flags": "w", "defaultEncoding": "utf8" });
          writeStream.on('error', (error) => {
            callback(error);
          });

          Array.prototype.forEach.call(instance.buffer, function(item, index){
            writeStream.write(item);
          });

          writeStream.end();
        }
        this.push(null);
        callback();
      }, (error) => {
        callback(error);
      });
    }
  }

  /**
   * Returns true if the passed value is null or undefined.
   *
   * ```javascript
   * BrowserifyPluginCanCompile.isNone();              // true
   * BrowserifyPluginCanCompile.isNone(null);          // true
   * BrowserifyPluginCanCompile.isNone(undefined);     // true
   * BrowserifyPluginCanCompile.isNone('');            // false
   * BrowserifyPluginCanCompile.isNone([]);            // false
   * BrowserifyPluginCanCompile.isNone(function() {});  // false
   * ```
   * @method isNone
   * @private
   * @static
   * @param {mixed} obj Value to test
   * @return {Boolean}
   */
  static isNone(obj) {
    return obj === null || obj === undefined;
  }
}

export default BrowserifyPluginCanCompile.addPlugin;<commit_msg>MOD: fixes bug in default normalizr<commit_after>/**
 * @package browserify-plugin-can-compile
 * @category javascript
 * @author scenecs <scenecs@t-online.de>
 */

'use strict';

import through2 from 'through2';
import canCompiler from 'can-compile';
import fs from 'fs';
import path from 'path';
import CanCompileScriptsCache from './library/CanCompileScriptsCache';
import es6Promise from 'es6-promise';

// Polyfill
es6Promise.polyfill();

/**
 * @property browserifyPluginCanCompileInstance
 * @private
 * @static
 * @type BrowserifyPluginCanCompile
 * @default undefined
 */
let browserifyPluginCanCompileInstance;

/**
 * Browserify Plugin: browserify-plugin-can-compile
 * =================================================
 *
 * A [Browserify](https://github.com/substack/node-browserify) plugin to require canJs template
 * files in a javascript file. The template will be precompiled with module "can-compile" and will
 * be bundled with the other javascript code. It is possible to save all required templates in an
 * external javascript file.
 *
 * b.plugin(BrowserifyPluginCanCompile.compile [, options])
 * ---------------------------------------------------------
 *
 * ### options
 *
 * The options object allows the following configuration options:
 *
 *    - `filename` {String}: The name of the file to be compiled
 *    - `version` {String}: The CanJS version to be used
 *    - `log` {Function}: A logger function (e..g `console.log.bind(console)`)
 *    - `normalizer` {Function}: A Function that returns the normalized path name
 *    - `tags` {Array}: A list of all your can.Component tags. They need to be registered in order to pre-compile views properly.
 *    - `extensions` {Object}: An object to map custom file extensions to the standard extension (e.g. `{ 'mst' : 'mustache' }`)
 *    - `viewAttributes` {Array}: A list of attribute names (RegExp or String), used for additional behavior for an attribute in a view (can.view.attr)
 *    - `paths` an object with `ejs`, `mustache` or `stache` and a `jquery` property pointing to files of existing versions or CanJS and jQuery instead of the CDN links.
 *
 * All options are optional. If the option `filename` is defined, the precompiled templates will be
 * saved in this external file.
 *
 * For more information please see at can-compile dokumentation: https://github.com/canjs/can-compile
 *
 * Example
 * --------
 *
 * ```javascript
 *  import browserify from 'browserify';
 *  import browserifyPluginCanCompile from 'browserify-plugin-can-compile';
 *
 *  let b = browserify();
 *
 *  b.add('./app.js')
 *   .plugin(browserifyPluginCanCompile, {
 *      "version": "2.3.23",
 *      "filename": "./views-app.js"
 *    })
 *   .bundle().pipe(process.stdout);
 * ```
 *
 * @class BrowserifyPluginCanCompile
 */
export class BrowserifyPluginCanCompile {
  /**
   *
   * @constructor
   * @param {Browserify} bundle Browserify instance
   * @see https://github.com/substack/node-browserify#browserifyfiles--opts
   * @param {Object} options Can-compile options to influence the compile process. This options will
   *    be piped to the module "can-compile".
   * @see https://github.com/canjs/can-compile#programmatically
   */
  constructor(bundle, options) {
    /**
     * @property buffer
     * @private
     * @type Array
     * @default []
     */
    this.buffer = [];

    /**
     * @property options
     * @private
     * @type Object
     * @default {
     *   "extensions": {
     *     "stache": "stache",
     *     "ejs": "ejs",
     *     "mustache": "mustache"
     *   }
     * }
     */
    this.options = {
      "extensions": {
        "stache": "stache",
        "ejs": "ejs",
        "mustache": "mustache"
      },
      "paths": undefined,
      "requirePaths": {
        'jquery': 'jquery',
        'can': 'can',
        'ejs': 'can/view/ejs/ejs',
        'stache': 'can/view/stache/stache',
        'mustache': 'can/view/mustache/mustache'
      },
      "filename": undefined,
      "version": undefined,
      "normalizer": undefined,
      "wrapper": 'module.exports = {{{content}}};',
      "wrapperForExternalTemplateFile": undefined,
      "cacheCanCompileScripts": true
    };

    /**
     * contains the passed browserify instance
     *
     * @property browserifyInstance
     * @type Browserify
     * @default undefined
     */
    this.browserifyInstance = undefined;

    /**
     * @property promise
     * @type Promise
     * @default Promise.resolve(this)
     */
    this.promise = Promise.resolve(this);

    if(!bundle || !bundle.pipeline) {
      throw new Error('The passed parameter "bundle" seems to be not a valid instance of "Browserify"!');
    }
    this.browserifyInstance = bundle;

    if(!options || !options.version) {
      throw new Error('Missing option "options.version"! Pass the currently used version of canJS.');
    }
    this.setOptions(options);

    if(this.constructor.isNone(this.options.normalizer)) {
      this.options.normalizer = this.getDefaultNormalizer();
    }

    if(this.constructor.isNone(this.options.paths) && true === this.options.cacheCanCompileScripts) {
      this.promise = new Promise((resolve, reject) => {
        let canCompileScriptsCache = CanCompileScriptsCache.createCache(this.options.version);

        /* istanbul ignore next */
        canCompileScriptsCache.on("finish", (files) => {
          this.setPaths(files);
          resolve(this);
        });

        /* istanbul ignore next */
        canCompileScriptsCache.on('error', (error) => {
          reject(error);
        });
      });
    }

    this.extendBrowserifyPipeline();
  }

  /**
   * @method setOptions
   * @private
   * @chainable
   * @param {Object} options
   * @return {BrowserifyPluginCanCompile}
   */
  setOptions(options) {
    if('object' !== typeof options || Array.isArray(options)) {
      throw new Error('The passed parameter "options" must be an object!');
    }

    Array.prototype.forEach.call(Object.keys(options), (key, index) => {
      this.options[key] = options[key];
    });

    return this;
  }

  /**
   * @method getOptions
   * @private
   * @return {Object} Returns the options.
   */
  getOptions() {
    return this.options;
  }

  /**
   * @method setPaths
   * @private
   * @chainable
   * @param {Array} paths
   * @return {BrowserifyPluginCanCompile}
   */
  setPaths(paths) {
    if(!Array.isArray(paths)) {
      throw new Error('The passed parameter "paths" must be an array!');
    }

    this.options.paths = paths;
    return this;
  }

  /**
   * @method getPaths
   * @private
   * @return {Array} Return an array of the path of the vendor scripts.
   */
  getPaths() {
    return this.options.paths;
  }

  /**
   * @method extendBrowserifyPipeline
   * @private
   */
  extendBrowserifyPipeline() {
    const instance = this.browserifyInstance;
    instance.transform(BrowserifyPluginCanCompile.transform);
  }

  /**
   * Creates a Regular Expressions for the defined template extensions.
   *
   * @method getFileExtensionRegExp
   * @private
   * @return {RegExp} Returns the generated Regular Expressions with capturing parentheses for
   *    filename and file extension
   */
  getFileExtensionRegExp() {
    const optionExtensions = this.options.extensions;

    if("object" !== typeof optionExtensions || Array.isArray(optionExtensions)) {
      throw new Error('Option "extensions" must be a key-value object!');
    }

    let flags = "i";
    let fileExtensions = Object.keys(this.options.extensions).map(function(item, index){
      return item.replace(new RegExp("[^\\w-]", flags), "");
    });

    return new RegExp("^.*\\" + path.sep + "([\\w-]+)\\.(" + fileExtensions.join("|") + ")$", flags);
  }

  /**
   * The normalizer returns a normalized key for the parsed template. With this key is it possible
   *    to call the template in the application. By default, the key is the filename of the template.
   *
   * The normalizer can be overwritten via plugin configuration. For more information please see
   *    at can-compile dokumentation: https://github.com/canjs/can-compile
   *
   * @method getDefaultNormalizer
   * @private
   * @return {String} Returns the key for the rendered can template.
   *
   * @see https://github.com/canjs/can-compile#programmatically
   */
  getDefaultNormalizer() {
    let fileExtRegEx = this.getFileExtensionRegExp();

    return function normalizer(file){
      let filename;

      try {
        filename = (Array.prototype.splice.call(fileExtRegEx.exec(file), 1, 1)).join("");
      } catch(err) {
        filename = file;
      }

      return filename;
    }
  }

  /**
   * @method addPlugin
   * @static
   * @param {Browserify} bundle Browserify instance
   * @see https://github.com/substack/node-browserify#browserifyfiles--opts
   * @param {Object} options Can-compile options to influence the compile process. This options will
   *    be piped to the module "can-compile".
   * @see https://github.com/canjs/can-compile#programmatically
   * @return {BrowserifyPluginCanCompile}
   */
  static addPlugin(bundle, options) {
    let instance;

    try {
      instance = BrowserifyPluginCanCompile.getInstance();
    } catch(error) {
      browserifyPluginCanCompileInstance = instance = new BrowserifyPluginCanCompile(bundle, options);
    }
    return instance;
  }

  /**
   * @method getInstance
   * @static
   * @return {BrowserifyPluginCanCompile} Returns the current instance
   */
  static getInstance() {
    if(!browserifyPluginCanCompileInstance) {
      throw new Error('No existing "BrowserifyPluginCanCompile" instance! Create a new instance with "browserifyPluginCanCompile.addPlugin(bundle, options)"');
    }

    return browserifyPluginCanCompileInstance;
  }

  /**
   * @method reset
   * @static
   */
  static reset() {
    browserifyPluginCanCompileInstance = undefined;
  }

  /**
   * @method transform
   * @static
   * @private
   * @param {String} file path of the current file
   * @return {BrowserifyPluginCanCompile}
   */
  static transform(file) {
    const instance = BrowserifyPluginCanCompile.getInstance();
    const fileExtRegEx = instance.getFileExtensionRegExp();

    if(!fileExtRegEx.test(file)) {
      return through2.obj();
    }

    return through2.obj(BrowserifyPluginCanCompile.transformFunction(file), BrowserifyPluginCanCompile.flushFunction());
  }

  /**
   * @method transformFunction
   * @private
   * @static
   * @param {String} file
   * @return {Function} Returns the transform function
   */
  static transformFunction(file) {
    const _file = file;

    return function transform(chunk, encoding, callback){
      let currentInstance = BrowserifyPluginCanCompile.getInstance();
      currentInstance.promise.then((instance) => {
        let options = instance.getOptions();
        let currentWrapper = options.wrapper;

        if(!BrowserifyPluginCanCompile.isNone(options.filename)) {
          currentWrapper = options.wrapperForExternalTemplateFile;
        }

        canCompiler(_file, options, (err, result) => {
          if(err) {
            return callback(err);
          }
          let bufferedResult = new Buffer(result, "utf8");

          if(BrowserifyPluginCanCompile.isNone(options.filename)){
            chunk = bufferedResult;
          } else {
            Array.prototype.push.call(instance.buffer, bufferedResult);
            chunk = new Buffer("module.export = can.view('" + options.normalizer(_file) + "');", "utf8");
          }

          this.push(chunk);
          callback();
        });
      }, (error) => {
        callback(error);
      });
    }
  }

  /**
   * @method flushFunction
   * @private
   * @static
   * @return {Function} Returns the flush function
   */
  static flushFunction() {

    return function flush(callback){
      let currentInstance = BrowserifyPluginCanCompile.getInstance();

      currentInstance.promise.then((instance) => {
        let options = instance.getOptions();

        if(!BrowserifyPluginCanCompile.isNone(options.filename)) {
          let writeStream;
          let file = path.normalize(options.filename);
          let filePath = path.dirname(file);

          mkdirp.sync(filePath);
          writeStream = fs.createWriteStream(file, { "flags": "w", "defaultEncoding": "utf8" });
          writeStream.on('error', (error) => {
            callback(error);
          });

          Array.prototype.forEach.call(instance.buffer, function(item, index){
            writeStream.write(item);
          });

          writeStream.end();
        }
        this.push(null);
        callback();
      }, (error) => {
        callback(error);
      });
    }
  }

  /**
   * Returns true if the passed value is null or undefined.
   *
   * ```javascript
   * BrowserifyPluginCanCompile.isNone();              // true
   * BrowserifyPluginCanCompile.isNone(null);          // true
   * BrowserifyPluginCanCompile.isNone(undefined);     // true
   * BrowserifyPluginCanCompile.isNone('');            // false
   * BrowserifyPluginCanCompile.isNone([]);            // false
   * BrowserifyPluginCanCompile.isNone(function() {});  // false
   * ```
   * @method isNone
   * @private
   * @static
   * @param {mixed} obj Value to test
   * @return {Boolean}
   */
  static isNone(obj) {
    return obj === null || obj === undefined;
  }
}

export default BrowserifyPluginCanCompile.addPlugin;<|endoftext|>