<commit_before>VSTOOLS.Text = {

	convert: function( i, len, end ) {

		len = len || i.length;

		var s = '';
		var j = 0;

		while ( j < len ) {

			if ( i[j] === 0xFA ) { // control code 0xFA

				if ( i[j + 1] === 0x06 ) { // space

					s += ' ';
					j += 2;

				} else { // TODO unknown

					// s += '{0xfa' + hex(i[j + 1]) + '}';
					j += 2;

				}
			} else if ( i[j] === 0xF8 ) { // control code 0xF8

				// unknown, skip
				j += 2;

			} else if ( i[j] === 0xFC ) { // control code 0xFC

				// unknown, skip
				j += 2;

			} else if ( i[j] === 0xFB ) { // control code 0xFB

				// unknown, skip
				j += 2;

			} else if ( i[j] === 0xE7 && end ) { // end of string

				return s;

			} else {

				s += VSTOOLS.Text.chr( i[j] );
				++j;

			}

		}

		return s;

	},

	chr: function( i ) {

		var c = VSTOOLS.Text.map[ i ];

		if ( c ) {

			return c;

		} else {

			return '{' + VSTOOLS.hex( i, 2 ) + '}';

		}

	}

};

(function() {

	var map = VSTOOLS.Text.map = new Array( 0xE9 );

	// 0 - 9
	for ( var i = 0; i <= 0x09; ++i ) {

		put( i, String.fromCharCode( i + 0x30 ) );

	}

	// A - Z
	for ( var i = 0x0A; i <= 0x23; ++i ) {

		put( i, String.fromCharCode( i + 0x41 - 0x0A ) );

	}

	// a - z
	for ( var i = 0x24; i <= 0x3D; ++i ) {

		put( i, String.fromCharCode( i + 0x61 - 0x24 ) );

	}

	put( 0x40, '_' );
	put( 0x41, '' );
	put( 0x42, '' );
	put( 0x43, '' );
	put( 0x44, '' );
	put( 0x45, '' );
	put( 0x46, '' );
	put( 0x47, '' );
	put( 0x48, '' );
	put( 0x49, '_' );
	put( 0x4A, '' );
	put( 0x4B, '_' );
	put( 0x4C, '' );
	put( 0x4D, '' );
	put( 0x4E, '' );
	put( 0x4F, '' );
	put( 0x50, '' );
	put( 0x51, '' );
	put( 0x52, '' );
	put( 0x53, '' );
	put( 0x54, '' );
	put( 0x55, '' );
	put( 0x56, '' );
	put( 0x57, '' );
	put( 0x58, '' );
	put( 0x59, '' );
	put( 0x5A, '' );
	put( 0x5B, '' );
	put( 0x5C, '' );
	put( 0x5D, '' );
	put( 0x5E, '' );
	put( 0x5F, '' );
	put( 0x60, '' );
	put( 0x61, '' );
	put( 0x62, '' );
	put( 0x63, '' );
	put( 0x64, '' );
	put( 0x65, '' );
	put( 0x66, '' );
	put( 0x67, '' );
	put( 0x68, '' );
	put( 0x69, '' );
	put( 0x6A, '' );

	put(0x8f, ' ');

	// long dash
	put( 0x8d, '--' );

	put( 0x90, '!' );
	put( 0x91, "'" );

	put( 0x94, '%' );

	put( 0x96, '\'' );
	put( 0x97, '( ' );
	put( 0x98, ' )' );

	put( 0x9B, '[' );
	put( 0x9C, ']' );
	put( 0x9D, ';' );
	put( 0x9E, ':' );
	put( 0x9F, ',' );
	put( 0xA0, '.' );
	put( 0xA1, '/' );
	put( 0xA2, '\\' );
	put( 0xA3, '<' );
	put( 0xA4, '>' );
	put( 0xA5, '?' );

	put( 0xA7, '-' );
	put( 0xA8, '+' );

	put( 0xB6, 'Lv.' ); // TODO what's this?

	put( 0xE8, '\n' );

	function put( i, c ) {

		map[i] = c;

	}

})();
<commit_msg>Text.js utf-8 and function keyword<commit_after>VSTOOLS.Text = {

	convert: function ( i, len, end ) {

		len = len || i.length;

		var s = '';
		var j = 0;

		while ( j < len ) {

			if ( i[j] === 0xFA ) { // control code 0xFA

				if ( i[j + 1] === 0x06 ) { // space

					s += ' ';
					j += 2;

				} else { // TODO unknown

					// s += '{0xfa' + hex(i[j + 1]) + '}';
					j += 2;

				}
			} else if ( i[j] === 0xF8 ) { // control code 0xF8

				// unknown, skip
				j += 2;

			} else if ( i[j] === 0xFC ) { // control code 0xFC

				// unknown, skip
				j += 2;

			} else if ( i[j] === 0xFB ) { // control code 0xFB

				// unknown, skip
				j += 2;

			} else if ( i[j] === 0xE7 && end ) { // end of string

				return s;

			} else {

				s += VSTOOLS.Text.chr( i[j] );
				++j;

			}

		}

		return s;

	},

	chr: function ( i ) {

		var c = VSTOOLS.Text.map[ i ];

		if ( c ) {

			return c;

		} else {

			return '{' + VSTOOLS.hex( i, 2 ) + '}';

		}

	}

};

( function () {

	var map = VSTOOLS.Text.map = new Array( 0xE9 );

	// 0 - 9
	for ( var i = 0; i <= 0x09; ++i ) {

		put( i, String.fromCharCode( i + 0x30 ) );

	}

	// A - Z
	for ( var i = 0x0A; i <= 0x23; ++i ) {

		put( i, String.fromCharCode( i + 0x41 - 0x0A ) );

	}

	// a - z
	for ( var i = 0x24; i <= 0x3D; ++i ) {

		put( i, String.fromCharCode( i + 0x61 - 0x24 ) );

	}

	put( 0x40, '_' );
	put( 0x41, 'Â' );
	put( 0x42, 'Ä' );
	put( 0x43, 'Ç' );
	put( 0x44, 'È' );
	put( 0x45, 'É' );
	put( 0x46, 'Ê' );
	put( 0x47, 'Ë' );
	put( 0x48, 'Ì' );
	put( 0x49, '_' );
	put( 0x4A, 'Î' );
	put( 0x4B, '_' );
	put( 0x4C, 'Ò' );
	put( 0x4D, 'Ó' );
	put( 0x4E, 'Ô' );
	put( 0x4F, 'Ö' );
	put( 0x50, 'Ù' );
	put( 0x51, 'Ú' );
	put( 0x52, 'Û' );
	put( 0x53, 'Ü' );
	put( 0x54, 'ß' );
	put( 0x55, 'æ' );
	put( 0x56, 'à' );
	put( 0x57, 'á' );
	put( 0x58, 'â' );
	put( 0x59, 'ä' );
	put( 0x5A, 'ç' );
	put( 0x5B, 'è' );
	put( 0x5C, 'é' );
	put( 0x5D, 'ê' );
	put( 0x5E, 'ë' );
	put( 0x5F, 'ì' );
	put( 0x60, 'í' );
	put( 0x61, 'î' );
	put( 0x62, 'ï' );
	put( 0x63, 'ò' );
	put( 0x64, 'ó' );
	put( 0x65, 'ô' );
	put( 0x66, 'ö' );
	put( 0x67, 'ù' );
	put( 0x68, 'ú' );
	put( 0x69, 'û' );
	put( 0x6A, 'ü' );

	put(0x8f, ' ');

	// long dash
	put( 0x8d, '--' );

	put( 0x90, '!' );
	put( 0x91, "'" );

	put( 0x94, '%' );

	put( 0x96, '\'' );
	put( 0x97, '( ' );
	put( 0x98, ' )' );

	put( 0x9B, '[' );
	put( 0x9C, ']' );
	put( 0x9D, ';' );
	put( 0x9E, ':' );
	put( 0x9F, ',' );
	put( 0xA0, '.' );
	put( 0xA1, '/' );
	put( 0xA2, '\\' );
	put( 0xA3, '<' );
	put( 0xA4, '>' );
	put( 0xA5, '?' );

	put( 0xA7, '-' );
	put( 0xA8, '+' );

	put( 0xB6, 'Lv.' ); // TODO what's this?

	put( 0xE8, '\n' );

	function put( i, c ) {

		map[i] = c;

	}

} )();
<|endoftext|>


<commit_before>'use strict';

const DEFAULT_EPUB_TITLE = '*';

const searchIndexSource = require('search-index'),
    Q = require('q'),
    searchIndex = Q.denodeify(searchIndexSource),
    colors = require('colors'),
    path = require('path'),
    fs = require('extfs'),
    _ = require('lodash'),
    preparer = require('./Preparer.js'),
    cfi = require('./CFI.js');

module.exports = function (options) {

    var SearchEngine = {};

    const INDEX_DB = 'full-text-search-DB'; // path to index-db
    var defaultOption = {'indexPath': INDEX_DB};
    var options = _.isEmpty(options) ? defaultOption : options;

    SearchEngine.indexing = function (pathToEpubs) {

        if (fs.isEmptySync(pathToEpubs)) {
            return Q.reject(new Error('Can`t index empty folder: ' + pathToEpubs));
        }
        console.log("\n\n\n******************************************************\n");
        console.log("Start normalize epub content\n\n".yellow);

        // normalize the directory path
        pathToEpubs = path.normalize(pathToEpubs);

        return preparer.normalize(pathToEpubs, options)
            .then(function (dataSet) {
                console.log("\n******************************************************\n");
                console.log("Ready with normalize epub content\n\n".yellow);

                if (dataSet.length > 0)
                    console.log("Start writing epub-data to index.");
                else {
                    console.log("DONE! Nothing to do, epubs already indexed.\n\n");
                    return;
                }

                return SearchEngine.add(dataSet);
            });
    };

    SearchEngine.add = function (jsonDoc) {

        var ids = jsonDoc.FirstSpineItemsId;
        delete jsonDoc.FirstSpineItemsId;

        return SearchEngine._add(jsonDoc, getIndexOptions());
    };

    SearchEngine.search = function (searchFor, bookTitle) {

        bookTitle = bookTitle || DEFAULT_EPUB_TITLE; // * if bookTitle undefined return all hits

        var q = {};
        q.query =
            {
                AND: {
                    'epubTitle': [preparer.normalizeEpupTitle(bookTitle)],
                    'body': [searchFor]
                }
            };

        return SearchEngine.query(q, searchFor);
    };

    SearchEngine.query = function (query, searchFor) {

        return SearchEngine._search(query)
            .then(function (result) {
                const hits = [];

                if (!result.hits) {
                    return hits;
                }

                result.hits.forEach(function (hit) {
                    const document = hit.document,
                        idData = document.id.split(':');

                    document.id = idData[0];

                    const cfiList = cfi.generate({
                        "searchFor": searchFor,
                        "spineItemPath": document.spineItemPath,
                        "baseCfi": document.baseCfi
                    });

                    if (cfiList.length > 0) {
                        document.cfis = cfiList;
                        delete document['*'];
                        delete document.spineItemPath;

                        hits.push(document);
                    }

                });
                return hits;
            });
    };

    SearchEngine.match = function (beginsWith, epubTitle) {

        if (!_.isString(epubTitle) && !_.isNull(epubTitle))
            console.error('epubTitle should be null or type string');

        var epubTitle = epubTitle || DEFAULT_EPUB_TITLE;

        return SearchEngine._match({beginsWith: beginsWith, type: 'ID'})
            .then(function (matches) {
                return filterMatches(matches, epubTitle);
            });
    };

    SearchEngine.empty = function () {
        return SearchEngine._empty();
    };

    SearchEngine.close = function () {
        return SearchEngine._close();
    };

// private
    function getIndexOptions() {
        return {
            fieldOptions: [
                {fieldName: 'epubTitle', searchable: false, store: true},
                {fieldName: 'spineItemPath', searchable: false, store: true},
                {fieldName: 'href', searchable: false, store: true},
                {fieldName: 'baseCfi', searchable: false, store: true},
                {fieldName: 'id', searchable: false, store: true},
                {fieldName: 'filename', searchable: true, store: true},
                {fieldName: 'title', searchable: true, store: false},
                {fieldName: 'body', searchable: true, store: false}
            ]
        };
    }

    function filterMatches(matches, epubTitle) {

        return matches
            .map(function (match) {

                if (epubTitle === '*') {
                    // if epubTitle undefined return all matches
                    return match[0];
                } else {
                    var titles = match[1].map(function (id) {
                        // id = spineitemid:epubtitle
                        return id.split(':')[1]
                    });
                    return _.include(titles, epubTitle) ? match[0] : '';
                }
            })
            .filter(Boolean); // filter ["", "", ""] -> []
    }

    return searchIndex(options)
        .then(function (si) {
            SearchEngine.si = si;
            SearchEngine._search = Q.nbind(si.search, si);
            SearchEngine._close = Q.nbind(si.close, si);
            SearchEngine._empty = Q.nbind(si.empty, si);
            SearchEngine._match = Q.nbind(si.match, si);
            SearchEngine._add = Q.nbind(si.add, si);
            return SearchEngine;
        });
};

/* require('search-index')({
 nGramLength: [1, 2, 3],   // allow phrase search on phrases of length 1, 2 and 3 words
 stopwords: []             // dont strip out stopwords
 }, function(err, si) {
 si.add([
 {date: 1464122926, text: 'some text'},
 {date: 1464122916, text: 'some another text'}
 ], function (err) {
 if (! err) {
 var q = {};
 q.query = { AND: [{'*': ['text']}] };
 si.search(q, function (err, results) {
 console.log(results);
 })
 }
 })
 })
 1. Use nGramLength to activate phrase search

 2. Set stopwords to []. By default, search-index will remove common english words like 'some' and 'another',
 so you need to empty your stopword list to allow them to
  be searchable (you could also remove them from the stopword list individually) */<commit_msg>-  set user home as default path for index db<commit_after>'use strict';

const DEFAULT_EPUB_TITLE = '*';

const searchIndexSource = require('search-index'),
    Q = require('q'),
    searchIndex = Q.denodeify(searchIndexSource),
    colors = require('colors'),
    path = require('path'),
    fs = require('extfs'),
    _ = require('lodash'),
    preparer = require('./Preparer.js'),
    cfi = require('./CFI.js'),
    osHomedir = require('os-homedir');

module.exports = function (options) {

    var SearchEngine = {};

    const INDEX_DB = path.join(osHomedir(), '.epub-full-text-search');
    var defaultOption = {'indexPath': INDEX_DB};
    var options = _.isEmpty(options) ? defaultOption : options;

    SearchEngine.indexing = function (pathToEpubs) {

        if (fs.isEmptySync(pathToEpubs)) {
            return Q.reject(new Error('Can`t index empty folder: ' + pathToEpubs));
        }
        console.log("\n\n\n******************************************************\n");
        console.log("Start normalize epub content\n\n".yellow);

        // normalize the directory path
        pathToEpubs = path.normalize(pathToEpubs);

        return preparer.normalize(pathToEpubs, options)
            .then(function (dataSet) {
                console.log("\n******************************************************\n");
                console.log("Ready with normalize epub content\n\n".yellow);

                if (dataSet.length > 0)
                    console.log("Start indexing epub-data.");
                else {
                    console.log("DONE! Nothing to do, epubs already indexed.\n\n");
                    return;
                }

                return SearchEngine.add(dataSet);
            });
    };

    SearchEngine.add = function (jsonDoc) {

        var ids = jsonDoc.FirstSpineItemsId;
        delete jsonDoc.FirstSpineItemsId;

        return SearchEngine._add(jsonDoc, getIndexOptions());
    };

    SearchEngine.search = function (searchFor, bookTitle) {

        bookTitle = bookTitle || DEFAULT_EPUB_TITLE; // * if bookTitle undefined return all hits

        var q = {};
        q.query =
            {
                AND: {
                    'epubTitle': [preparer.normalizeEpupTitle(bookTitle)],
                    'body': [searchFor]
                }
            };

        return SearchEngine.query(q, searchFor);
    };

    SearchEngine.query = function (query, searchFor) {

        return SearchEngine._search(query)
            .then(function (result) {
                const hits = [];

                if (!result.hits) {
                    return hits;
                }

                result.hits.forEach(function (hit) {
                    const document = hit.document,
                        idData = document.id.split(':');

                    document.id = idData[0];

                    const cfiList = cfi.generate({
                        "searchFor": searchFor,
                        "spineItemPath": document.spineItemPath,
                        "baseCfi": document.baseCfi
                    });

                    if (cfiList.length > 0) {
                        document.cfis = cfiList;
                        delete document['*'];
                        delete document.spineItemPath;

                        hits.push(document);
                    }

                });
                return hits;
            });
    };

    SearchEngine.match = function (beginsWith, epubTitle) {

        if (!_.isString(epubTitle) && !_.isNull(epubTitle))
            console.error('epubTitle should be null or type string');

        var epubTitle = epubTitle || DEFAULT_EPUB_TITLE;

        return SearchEngine._match({beginsWith: beginsWith, type: 'ID'})
            .then(function (matches) {
                return filterMatches(matches, epubTitle);
            });
    };

    SearchEngine.empty = function () {
        return SearchEngine._empty();
    };

    SearchEngine.close = function () {
        return SearchEngine._close();
    };

// private
    function getIndexOptions() {
        return {
            fieldOptions: [
                {fieldName: 'epubTitle', searchable: false, store: true},
                {fieldName: 'spineItemPath', searchable: false, store: true},
                {fieldName: 'href', searchable: false, store: true},
                {fieldName: 'baseCfi', searchable: false, store: true},
                {fieldName: 'id', searchable: false, store: true},
                {fieldName: 'filename', searchable: true, store: true},
                {fieldName: 'title', searchable: true, store: false},
                {fieldName: 'body', searchable: true, store: false}
            ]
        };
    }

    function filterMatches(matches, epubTitle) {

        return matches
            .map(function (match) {

                if (epubTitle === '*') {
                    // if epubTitle undefined return all matches
                    return match[0];
                } else {
                    var titles = match[1].map(function (id) {
                        // id = spineitemid:epubtitle
                        return id.split(':')[1]
                    });
                    return _.include(titles, epubTitle) ? match[0] : '';
                }
            })
            .filter(Boolean); // filter ["", "", ""] -> []
    }

    return searchIndex(options)
        .then(function (si) {
            SearchEngine.si = si;
            SearchEngine._search = Q.nbind(si.search, si);
            SearchEngine._close = Q.nbind(si.close, si);
            SearchEngine._empty = Q.nbind(si.empty, si);
            SearchEngine._match = Q.nbind(si.match, si);
            SearchEngine._add = Q.nbind(si.add, si);
            return SearchEngine;
        });
};

/* require('search-index')({
 nGramLength: [1, 2, 3],   // allow phrase search on phrases of length 1, 2 and 3 words
 stopwords: []             // dont strip out stopwords
 }, function(err, si) {
 si.add([
 {date: 1464122926, text: 'some text'},
 {date: 1464122916, text: 'some another text'}
 ], function (err) {
 if (! err) {
 var q = {};
 q.query = { AND: [{'*': ['text']}] };
 si.search(q, function (err, results) {
 console.log(results);
 })
 }
 })
 })
 1. Use nGramLength to activate phrase search

 2. Set stopwords to []. By default, search-index will remove common english words like 'some' and 'another',
 so you need to empty your stopword list to allow them to
  be searchable (you could also remove them from the stopword list individually) */<|endoftext|>


<commit_before>/*
 * Fuel UX Picker
 * https://github.com/ExactTarget/fuelux
 *
 * Copyright (c) 2014 ExactTarget
 * Licensed under the BSD New license.
 */

// -- BEGIN UMD WRAPPER PREFACE --

// For more information on UMD visit:
// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js

(function (factory) {
	if (typeof define === 'function' && define.amd) {
		// if AMD loader is available, register as an anonymous module.
		define(['jquery'], factory);
	} else if (typeof exports === 'object') {
		// Node/CommonJS
		module.exports = factory(require('jquery'));
	} else {
		// OR use browser globals if AMD is not present
		factory(jQuery);
	}
}(function ($) {
	// -- END UMD WRAPPER PREFACE --

	// -- BEGIN MODULE CODE HERE --

	var old = $.fn.picker;
	var EVENT_CALLBACK_MAP = { 'accepted': 'onAccept', 'cancelled': 'onCancel' };
	var DEFAULT_HEIGHT = 234;
	var DEFAULT_WIDTH = 350;

	// PLACARD CONSTRUCTOR AND PROTOTYPE

	var Picker = function Picker(element, options) {
		var self = this;
		this.$element = $(element);
		this.options = $.extend({}, $.fn.picker.defaults, options);

		this.$accept = this.$element.find('.picker-accept');
		this.$cancel = this.$element.find('.picker-cancel');
		this.$trigger = this.$element.find('.picker-trigger');
		this.$footer = this.$element.find('.picker-footer');
		this.$header = this.$element.find('.picker-header');
		this.$popup = this.$element.find('.picker-popup');
		this.$body = this.$element.find('.picker-body');

		this.clickStamp = '_';

		this.isInput = this.$trigger.is('input');

		this.$trigger.on('keydown.fu.picker', $.proxy(this.keyComplete, this));
		this.$trigger.on('focus.fu.picker', $.proxy(function inputFocus(e){
			$.proxy(this.show(), this);
		}, this));
		this.$trigger.on('click.fu.picker', $.proxy(function triggerClick(e){
			if(!$(e.target).is('input[type=text]')){
				$.proxy(this.toggle(), this);
			}else{
				$.proxy(this.show(), this);
			}
		}, this));
		this.$accept.on('click.fu.picker', $.proxy(this.complete, this, 'accepted'));
		this.$cancel.on('click.fu.picker', function (e) {
			e.preventDefault(); self.complete('cancelled');
		});

	};

	var _isOffscreen = function _isOffscreen(picker) {
		var windowHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
		var scrollTop = $(document).scrollTop();
		var popupTop = picker.$popup.offset();
		var popupBottom = popupTop.top + picker.$popup.outerHeight(true);

		//if the bottom of the popup goes off the page, but the top does not, dropup.
		if (popupBottom > windowHeight + scrollTop || popupTop.top < scrollTop){
			return true;
		}else{//otherwise, prefer showing the top of the popup only vs the bottom
			return false;
		}
	};

	var _display = function _display(picker) {
		picker.$popup.css('visibility', 'hidden');

		_showBelow(picker);

		//if part of the popup is offscreen try to show it above
		if(_isOffscreen(picker)){
			_showAbove(picker);

			//if part of the popup is still offscreen, prefer cutting off the bottom
			if(_isOffscreen(picker)){
				_showBelow(picker);
			}
		}

		picker.$popup.css('visibility', 'visible');
	};

	var _showAbove = function _showAbove(picker) {
		picker.$popup.css('height', (picker.options.height)?picker.options.height : DEFAULT_HEIGHT + 'px');
		picker.$body.css('height', ((picker.options.height)?picker.options.height : DEFAULT_HEIGHT) - 73 + 'px');
		picker.$popup.css('width', (picker.options.width)?picker.options.height : DEFAULT_WIDTH + 'px');
		picker.$popup.css('top', -(picker.$popup.outerHeight(true) + 4) + 'px');
	};

	var _showBelow = function _showBelow(picker) {
		picker.$popup.css('top', (picker.$trigger.outerHeight(true)+4) + 'px');
		picker.$popup.css('height', (picker.options.height)?picker.options.height : DEFAULT_HEIGHT + 'px');
		picker.$body.css('height', ((picker.options.height)?picker.options.height : DEFAULT_HEIGHT) - 73 + 'px');
		picker.$popup.css('width', (picker.options.width)?picker.options.height : DEFAULT_WIDTH + 'px');
	};

	Picker.prototype = {
		constructor: Picker,

		complete: function complete(action) {
			var func = this.options[ EVENT_CALLBACK_MAP[action] ];

			var obj = {
				contents: this.$body
			};

			if (func) {
				func(obj);
				this.$element.trigger(action + '.fu.picker', obj);
			} else {
				this.$element.trigger(action + '.fu.picker', obj);
				this.hide();
			}
		},

		keyComplete: function keyComplete(e) {
			if (this.isInput && e.keyCode === 13) {
				this.complete('accepted');
				this.$trigger.blur();
			} else if (e.keyCode === 27) {
				this.complete('cancelled');
				this.$trigger.blur();
			}
		},

		destroy: function destroy() {
			this.$element.remove();
			// remove any external bindings
			$(document).off('click.fu.picker.externalClick.' + this.clickStamp);
			// set input value attribute
			this.$element.find('input').each(function () {
				$(this).attr('value', $(this).val());
			});
			// empty elements to return to original markup
			// [none]
			// return string of markup
			return this.$element[0].outerHTML;
		},

		disable: function disable() {
			this.$element.addClass('disabled');
			this.$trigger.attr('disabled', 'disabled');
		},

		enable: function enable() {
			this.$element.removeClass('disabled');
			this.$trigger.removeAttr('disabled');
		},

		toggle: function toggle() {
			if (this.$element.hasClass('showing')) {
				this.hide();
			}else{
				this.show();
			}
		},

		hide: function hide() {
			if (!this.$element.hasClass('showing')) {
				return;
			}

			this.$element.removeClass('showing');
			$(document).off('click.fu.picker.externalClick.' + this.clickStamp);
			this.$element.trigger('hidden.fu.picker');
		},

		externalClickListener: function externalClickListener(e, force) {
			if (force === true || this.isExternalClick(e)) {
				this.complete('exit');
			}
		},

		isExternalClick: function isExternalClick(e) {
			var el = this.$element.get(0);
			var exceptions = this.options.externalClickExceptions || [];
			var $originEl = $(e.target);
			var i, l;

			if (e.target === el || $originEl.parents('.picker:first').get(0) === el) {
				return false;
			} else {
				for (i = 0, l = exceptions.length; i < l; i++) {
					if ($originEl.is(exceptions[i]) || $originEl.parents(exceptions[i]).length > 0) {
						return false;
					}

				}
			}

			return true;
		},

		show: function show() {
			var other;

			if (this.$element.hasClass('showing')) {
				return;
			}

			other = $(document).find('.picker.showing');
			if (other.length > 0) {
				if (other.data('fu.picker') && other.data('fu.picker').options.explicit) {
					return;
				}

				other.picker('externalClickListener', {}, true);
			}

			this.$element.addClass('showing');

			_display(this);

			this.$element.trigger('shown.fu.picker');

			this.clickStamp = new Date().getTime() + (Math.floor(Math.random() * 100) + 1);
			if (!this.options.explicit) {
				$(document).on('click.fu.picker.externalClick.' + this.clickStamp, $.proxy(this.externalClickListener, this));
			}
		}
	};

	// PLACARD PLUGIN DEFINITION

	$.fn.picker = function picker(option) {
		var args = Array.prototype.slice.call(arguments, 1);
		var methodReturn;

		var $set = this.each(function () {
			var $this = $(this);
			var data = $this.data('fu.picker');
			var options = typeof option === 'object' && option;

			if (!data) {
				$this.data('fu.picker', (data = new Picker(this, options)));
			}

			if (typeof option === 'string') {
				methodReturn = data[option].apply(data, args);
			}
		});

		return (methodReturn === undefined) ? $set : methodReturn;
	};

	$.fn.picker.defaults = {
		onAccept: undefined,
		onCancel: undefined,
		onExit: undefined,
		externalClickExceptions: [],
		explicit: false
	};

	$.fn.picker.Constructor = Picker;

	$.fn.picker.noConflict = function noConflict() {
		$.fn.picker = old;
		return this;
	};

	// DATA-API

	$(document).on('focus.fu.picker.data-api', '[data-initialize=picker]', function (e) {
		var $control = $(e.target).closest('.picker');
		if (!$control.data('fu.picker')) {
			$control.picker($control.data());
		}
	});

	// Must be domReady for AMD compatibility
	$(function () {
		$('[data-initialize=picker]').each(function () {
			var $this = $(this);
			if ($this.data('fu.picker')) return;
			$this.picker($this.data());
		});
	});

	// -- BEGIN UMD WRAPPER AFTERWORD --
}));
// -- END UMD WRAPPER AFTERWORD --
<commit_msg>(picker) removes vestigial code<commit_after>/*
 * Fuel UX Picker
 * https://github.com/ExactTarget/fuelux
 *
 * Copyright (c) 2014 ExactTarget
 * Licensed under the BSD New license.
 */

// -- BEGIN UMD WRAPPER PREFACE --

// For more information on UMD visit:
// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js

(function (factory) {
	if (typeof define === 'function' && define.amd) {
		// if AMD loader is available, register as an anonymous module.
		define(['jquery'], factory);
	} else if (typeof exports === 'object') {
		// Node/CommonJS
		module.exports = factory(require('jquery'));
	} else {
		// OR use browser globals if AMD is not present
		factory(jQuery);
	}
}(function ($) {
	// -- END UMD WRAPPER PREFACE --

	// -- BEGIN MODULE CODE HERE --

	var old = $.fn.picker;
	var EVENT_CALLBACK_MAP = { 'accepted': 'onAccept', 'cancelled': 'onCancel' };
	var DEFAULT_HEIGHT = 234;
	var DEFAULT_WIDTH = 350;

	// PLACARD CONSTRUCTOR AND PROTOTYPE

	var Picker = function Picker(element, options) {
		var self = this;
		this.$element = $(element);
		this.options = $.extend({}, $.fn.picker.defaults, options);

		this.$accept = this.$element.find('.picker-accept');
		this.$cancel = this.$element.find('.picker-cancel');
		this.$trigger = this.$element.find('.picker-trigger');
		this.$footer = this.$element.find('.picker-footer');
		this.$header = this.$element.find('.picker-header');
		this.$popup = this.$element.find('.picker-popup');
		this.$body = this.$element.find('.picker-body');

		this.clickStamp = '_';

		this.isInput = this.$trigger.is('input');

		this.$trigger.on('keydown.fu.picker', $.proxy(this.keyComplete, this));
		this.$trigger.on('focus.fu.picker', $.proxy(function inputFocus(e){
			$.proxy(this.show(), this);
		}, this));
		this.$trigger.on('click.fu.picker', $.proxy(function triggerClick(e){
			if(!$(e.target).is('input[type=text]')){
				$.proxy(this.toggle(), this);
			}else{
				$.proxy(this.show(), this);
			}
		}, this));
		this.$accept.on('click.fu.picker', $.proxy(this.complete, this, 'accepted'));
		this.$cancel.on('click.fu.picker', function (e) {
			e.preventDefault(); self.complete('cancelled');
		});

	};

	var _isOffscreen = function _isOffscreen(picker) {
		var windowHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
		var scrollTop = $(document).scrollTop();
		var popupTop = picker.$popup.offset();
		var popupBottom = popupTop.top + picker.$popup.outerHeight(true);

		//if the bottom of the popup goes off the page, but the top does not, dropup.
		if (popupBottom > windowHeight + scrollTop || popupTop.top < scrollTop){
			return true;
		}else{//otherwise, prefer showing the top of the popup only vs the bottom
			return false;
		}
	};

	var _display = function _display(picker) {
		picker.$popup.css('visibility', 'hidden');

		_showBelow(picker);

		//if part of the popup is offscreen try to show it above
		if(_isOffscreen(picker)){
			_showAbove(picker);

			//if part of the popup is still offscreen, prefer cutting off the bottom
			if(_isOffscreen(picker)){
				_showBelow(picker);
			}
		}

		picker.$popup.css('visibility', 'visible');
	};

	var _showAbove = function _showAbove(picker) {
		picker.$popup.css('height', (picker.options.height)?picker.options.height : DEFAULT_HEIGHT + 'px');
		picker.$body.css('height', ((picker.options.height)?picker.options.height : DEFAULT_HEIGHT) - 73 + 'px');
		picker.$popup.css('width', (picker.options.width)?picker.options.height : DEFAULT_WIDTH + 'px');
		picker.$popup.css('top', -(picker.$popup.outerHeight(true) + 4) + 'px');
	};

	var _showBelow = function _showBelow(picker) {
		picker.$popup.css('top', (picker.$trigger.outerHeight(true)+4) + 'px');
		picker.$popup.css('height', (picker.options.height)?picker.options.height : DEFAULT_HEIGHT + 'px');
		picker.$body.css('height', ((picker.options.height)?picker.options.height : DEFAULT_HEIGHT) - 73 + 'px');
		picker.$popup.css('width', (picker.options.width)?picker.options.height : DEFAULT_WIDTH + 'px');
	};

	Picker.prototype = {
		constructor: Picker,

		complete: function complete(action) {
			var func = this.options[ EVENT_CALLBACK_MAP[action] ];

			var obj = {
				contents: this.$body
			};

			if (func) {
				func(obj);
				this.$element.trigger(action + '.fu.picker', obj);
			} else {
				this.$element.trigger(action + '.fu.picker', obj);
				this.hide();
			}
		},

		keyComplete: function keyComplete(e) {
			if (this.isInput && e.keyCode === 13) {
				this.complete('accepted');
				this.$trigger.blur();
			} else if (e.keyCode === 27) {
				this.complete('cancelled');
				this.$trigger.blur();
			}
		},

		destroy: function destroy() {
			this.$element.remove();
			// remove any external bindings
			$(document).off('click.fu.picker.externalClick.' + this.clickStamp);
			// empty elements to return to original markup
			// [none]
			// return string of markup
			return this.$element[0].outerHTML;
		},

		disable: function disable() {
			this.$element.addClass('disabled');
			this.$trigger.attr('disabled', 'disabled');
		},

		enable: function enable() {
			this.$element.removeClass('disabled');
			this.$trigger.removeAttr('disabled');
		},

		toggle: function toggle() {
			if (this.$element.hasClass('showing')) {
				this.hide();
			}else{
				this.show();
			}
		},

		hide: function hide() {
			if (!this.$element.hasClass('showing')) {
				return;
			}

			this.$element.removeClass('showing');
			$(document).off('click.fu.picker.externalClick.' + this.clickStamp);
			this.$element.trigger('hidden.fu.picker');
		},

		externalClickListener: function externalClickListener(e, force) {
			if (force === true || this.isExternalClick(e)) {
				this.complete('exit');
			}
		},

		isExternalClick: function isExternalClick(e) {
			var el = this.$element.get(0);
			var exceptions = this.options.externalClickExceptions || [];
			var $originEl = $(e.target);
			var i, l;

			if (e.target === el || $originEl.parents('.picker:first').get(0) === el) {
				return false;
			} else {
				for (i = 0, l = exceptions.length; i < l; i++) {
					if ($originEl.is(exceptions[i]) || $originEl.parents(exceptions[i]).length > 0) {
						return false;
					}

				}
			}

			return true;
		},

		show: function show() {
			var other;

			if (this.$element.hasClass('showing')) {
				return;
			}

			other = $(document).find('.picker.showing');
			if (other.length > 0) {
				if (other.data('fu.picker') && other.data('fu.picker').options.explicit) {
					return;
				}

				other.picker('externalClickListener', {}, true);
			}

			this.$element.addClass('showing');

			_display(this);

			this.$element.trigger('shown.fu.picker');

			this.clickStamp = new Date().getTime() + (Math.floor(Math.random() * 100) + 1);
			if (!this.options.explicit) {
				$(document).on('click.fu.picker.externalClick.' + this.clickStamp, $.proxy(this.externalClickListener, this));
			}
		}
	};

	// PLACARD PLUGIN DEFINITION

	$.fn.picker = function picker(option) {
		var args = Array.prototype.slice.call(arguments, 1);
		var methodReturn;

		var $set = this.each(function () {
			var $this = $(this);
			var data = $this.data('fu.picker');
			var options = typeof option === 'object' && option;

			if (!data) {
				$this.data('fu.picker', (data = new Picker(this, options)));
			}

			if (typeof option === 'string') {
				methodReturn = data[option].apply(data, args);
			}
		});

		return (methodReturn === undefined) ? $set : methodReturn;
	};

	$.fn.picker.defaults = {
		onAccept: undefined,
		onCancel: undefined,
		onExit: undefined,
		externalClickExceptions: [],
		explicit: false
	};

	$.fn.picker.Constructor = Picker;

	$.fn.picker.noConflict = function noConflict() {
		$.fn.picker = old;
		return this;
	};

	// DATA-API

	$(document).on('focus.fu.picker.data-api', '[data-initialize=picker]', function (e) {
		var $control = $(e.target).closest('.picker');
		if (!$control.data('fu.picker')) {
			$control.picker($control.data());
		}
	});

	// Must be domReady for AMD compatibility
	$(function () {
		$('[data-initialize=picker]').each(function () {
			var $this = $(this);
			if ($this.data('fu.picker')) return;
			$this.picker($this.data());
		});
	});

	// -- BEGIN UMD WRAPPER AFTERWORD --
}));
// -- END UMD WRAPPER AFTERWORD --
<|endoftext|>


<commit_before>var meta = require('./package.json');

var del     = require('del');
var concat    = require('gulp-concat');
var csslint   = require('gulp-csslint');
var cssmin    = require('gulp-cssmin');
var download  = require('gulp-download');
var gulp      = require('gulp');
var jshint    = require('gulp-jshint');
var jeditor   = require('gulp-json-editor');
var phplint   = require('phplint');
var prompt    = require('gulp-prompt');
var uglify    = require('gulp-uglify');

/*
 * Task combos
 */
gulp.task('lint',   ['csslint', 'jshint', 'phplint']);
gulp.task('make',   ['cssmin', 'uglify']);
gulp.task('travis', ['csslint', 'jshint']);

// Task aliases
gulp.task('bs',          ['bootstrap']);
gulp.task('css',         ['csslint', 'cssmin']);
gulp.task('fa',          ['icons']);
gulp.task('fontawesome', ['icons']);
gulp.task('highlighter', ['hljs']);
gulp.task('js',          ['jshint', 'uglify']);
gulp.task('php',         ['phplint']);
gulp.task('theme',       ['hljs_theme']);
gulp.task('update',      ['upgrade']);

/*
 * SELF COPY
 *
 * Create file structure in app/, copy all PHP & .htaccess
 */
gulp.task('init', function() {

  gulp.src([
      'src/index.php',
      'src/listr-functions.php',
      'src/listr-l10n.php',
      'src/listr-template.php'
    ])
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/locale/**/*'
    ])
    .pipe(gulp.dest('app/locale/'));

  gulp.src([
      'src/config.json'
    ])
    .pipe(concat('config.json'))
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/root.htaccess'
    ])
    .pipe(concat('.htaccess'))
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/public.htaccess'
    ])
    .pipe(concat('.htaccess'))
    .pipe(gulp.dest('app/_public/'));
});

/*
 * UPGRADE
 *
 * Upgrade files in app/. Does not touch config.json and .htaccess files!
 */
gulp.task('upgrade', function() {

  del([
    'app/assets/css/listr.pack.css',
    'app/assets/js/listr.pack.js'
  ])

  gulp.src([
      'src/index.php',
      'src/listr-functions.php',
      'src/listr-l10n.php',
      'src/listr-template.php'
    ])
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/root.htaccess'
    ])
    .pipe(concat('.htaccess-example'))
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/locale/**/*'
    ])
    .pipe(gulp.dest('app/locale/'));
});

/*
 * CLEAN-UP
 *
 * Delete all files in app
 */
gulp.task('clean', function () {
  return del(['app/']);
});

gulp.task('reset', function () {
  gulp.src([
      'src/config.json'
    ])
    .pipe(gulp.dest('app/'));
});

/*
 * LINT PHP
 */
gulp.task('phplint', function () {
  return phplint([
        'src/*.php'
    ]);
});

/*
 * LINT CSS
 */
gulp.task('csslint', function() {
  gulp.src([
      'src/style.css'
    ])
    .pipe(csslint())
    .pipe(csslint.reporter())
});

/*
 * MINIFY CSS
 */
gulp.task('cssmin', function() {
  gulp.src([
      'src/style.css'
    ])
    .pipe(concat('listr.min.css'))
    .pipe(cssmin())
    .pipe(gulp.dest('app/assets/css/'))
});

/*
 * HINT JS
 */
gulp.task('jshint', function() {
  gulp.src([
      'src/config.json',
      'src/scripts.js'
    ])
    .pipe(jshint())
    .pipe(jshint.reporter())
});

/*
 * UGLIFY JS
 */
gulp.task('uglify', function() {
  gulp.src([
      'src/scripts.js'
    ])
    .pipe(uglify())
    .pipe(concat('listr.min.js'))
    .pipe(gulp.dest('app/assets/js/'))
});

/*
 * MERGE ASSETS
 */

gulp.task('post_merge', function() {
  del([
    'app/assets/css/*.css',
    '!app/assets/css/listr.pack.css',
    'app/assets/js/*.js',
    '!app/assets/js/jquery.min.js',
    '!app/assets/js/listr.pack.js'
  ])
});

gulp.task('merge', function(){

  gulp.src([
      'app/assets'
    ])

    .pipe(prompt.prompt({
        type: 'input',
        name: 'merge',
        message: 'Do you want to merge all assets?',
        default: 'y'
    }, function(res){
        if(res.merge === 'y') {
              gulp.src([
                  'app/assets/css/*.css',
                  '!app/assets/css/listr.pack.css'
                ])
                .pipe(concat('listr.pack.css'))
                .pipe(gulp.dest('app/assets/css/')),

                gulp.src([
                  'app/assets/js/*.js',
                  '!app/assets/js/jquery.min.js',
                  '!app/assets/js/listr.pack.js'
                ])
                .pipe(concat('listr.pack.js'))
                .pipe(gulp.dest('app/assets/js/'));

                gulp.src("app/config.json")
                .pipe(jeditor({
                  'general': {
                    'dependencies': "pack"
                  }
                }))
                .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * BOOTSTRAP THEME SETUP
 *
 * Pick a Bootstrap theme
 */
gulp.task('bootstrap', function(){

 var bootswatch = ['default','amelia','cerulean','cosmo','cyborg','darkly','flatly','journal','lumen','paper','readable','sandstone','simplex','slate','spacelab','superhero','united','yeti'];

 gulp.src('.')
    .pipe(prompt.prompt({
        type: 'input',
        name: 'bootstrap',
        message: 'Which Bootstrap theme would you like to use?',
        default: 'default',
        validate: function(pass){

            if (bootswatch.indexOf(pass) == -1 ) {
                return false;
            }

            return true;
        }
    }, function(res){

        if(res.bootstrap === 'default') {
              gulp.src('node_modules/bootstrap/dist/css/bootstrap.min.css')
              .pipe(concat('bootstrap.min.css'))
              .pipe(gulp.dest('app/assets/css/'))
              gulp.src("app/config.json")
                .pipe(jeditor({
                  'bootstrap': {
                    'theme': 'default'
                  }
                }))
                .pipe(gulp.dest("app/"));
        } else if (bootswatch.indexOf(res.bootstrap) != -1 ) {
              gulp.src('node_modules/bootswatch/' + res.bootstrap + '/bootstrap.min.css')
              .pipe(concat('bootstrap.min.css'))
              .pipe(gulp.dest('app/assets/css/')),

              gulp.src("app/config.json")
              .pipe(jeditor({
                'bootstrap': {
                  'theme': res.bootstrap
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));

  gulp.src([
  'node_modules/bootstrap/fonts/*'

  ])
  .pipe(gulp.dest('app/assets/fonts/'));

});

/*
 * VIEWER SETUP
 *
 * Copy dependencies for the viewer modal
 */
gulp.task('viewer', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'viewer',
        message: 'Do you want to make use of the viewer modal?',
        default: 'y'
    }, function(res){
        if(res.viewer === 'y') {
              gulp.src([
                'node_modules/bootstrap/dist/js/bootstrap.min.js',
                'node_modules/jquery/dist/jquery.min.js',
                'node_modules/jquery/dist/jquery.min.map'
              ])
              .pipe(gulp.dest('app/assets/js/'));

              gulp.src("app/config.json")
              .pipe(jeditor({
                'general': {
                  'enable_viewer': true
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * SEARCH BOX SETUP
 *
 * Copy dependencies for the search box
 */
gulp.task('search', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'search',
        message: 'Do you want to make use of the search box?',
        default: 'y'
    }, function(res){
        if(res.search === 'y') {
              gulp.src([
                'node_modules/jquery/dist/jquery.min.js',
                'node_modules/jquery/dist/jquery.min.map',
                'node_modules/jquery-searcher/dist/jquery.searcher.min.js'

              ])
              .pipe(gulp.dest('app/assets/js/'))

              gulp.src("app/config.json")
              .pipe(jeditor({
                'general': {
                  'enable_search': true
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * FONT AWESOME SETUP
 *
 * Copy dependencies for Font Awesome icons
 */
gulp.task('icons', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'fontawesome',
        message: 'Do you want to make use of Font Awesome icons?',
        default: 'y'
    }, function(res){
        if(res.fontawesome === 'y') {

              gulp.src([
                'node_modules/font-awesome/css/font-awesome.min.css'

              ])
              .pipe(gulp.dest('app/assets/css/'))

              gulp.src([
                'node_modules/font-awesome/fonts/*'

              ])
              .pipe(gulp.dest('app/assets/fonts/'))

              gulp.src("app/config.json")
              .pipe(jeditor({
                'bootstrap': {
                  'icons': 'fontawesome'
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * HIGHLIGHT.JS SETUP
 *
 * Copy dependencies for the syntax highlighter
 */
gulp.task('hljs', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'hljs',
        message: 'Do you want to make use of the syntax highlighter?',
        default: 'n'
    }, function(res){
        if(res.hljs === 'y') {
              download('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/highlight.min.js')
              .pipe(gulp.dest('app/assets/js/'))

              gulp.src("app/config.json")
              .pipe(jeditor({
                'general': {
                  'enable_highlight': true
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * HIGHLIGHT.JS THEME
 *
 * Pick a style-sheet for Highlight.js
 */
gulp.task('hljs_theme', function(){

 var hljs_theme = ['arta', 'ascetic', 'atelier-dune.dark', 'atelier-dune.light', 'atelier-forest.dark', 'atelier-forest.light', 'atelier-heath.dark', 'atelier-heath.light', 'atelier-lakeside.dark', 'atelier-lakeside.light', 'atelier-seaside.dark', 'atelier-seaside.light', 'brown_paper', 'dark', 'default', 'docco', 'far', 'foundation', 'github', 'googlecode', 'idea', 'ir_black', 'magula', 'mono-blue', 'monokai', 'monokai_sublime', 'obsidian', 'paraiso.dark', 'paraiso.light', 'pojoaque', 'railscasts', 'rainbow', 'school_book', 'solarized_dark', 'solarized_light', 'sunburst', 'tomorrow-night-blue', 'tomorrow-night-bright', 'tomorrow-night-eighties', 'tomorrow-night', 'tomorrow', 'vs', 'xcode', 'zenburn']

 gulp.src('.')
    .pipe(prompt.prompt({
        type: 'input',
        name: 'highlighter',
        message: 'Which Highlight.js theme would you like to use?',
        default: 'github',
        validate: function(pass){

            if (hljs_theme.indexOf(pass) == -1 ) {
                return false;
            }

            return true;
        }
    }, function(res){

        if (hljs_theme.indexOf(res.highlighter) != -1) {
          download('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/styles/' + res.highlighter + '.min.css')

          .pipe(concat('highlight.min.css'))
          .pipe(gulp.dest('app/assets/css/'));

          gulp.src("app/config.json")
          .pipe(jeditor({
            'highlight': {
              'theme': res.hljs_theme
            }
          }))
          .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * APACHE SERVER CONFIGS
 *
 * Append HTML5 Boilerplate's Apache rules to .htaccess
 */
gulp.task('apache', function(){

  gulp.src([
      'src/root.htaccess'
    ])

    .pipe(prompt.prompt({
        type: 'input',
        name: 'h5bp',
        message: 'Do you want to append H5BP\'s Apache Server Config rules?',
        default: 'y'
    }, function(res){
        if(res.h5bp === 'y') {
              gulp.src(['src/root.htaccess','node_modules/apache-server-configs/dist/.htaccess'])
              .pipe(concat('.htaccess'))
              .pipe(gulp.dest('app/'))
        }
    }));
});

/*
 * ROBOTS
 *
 * Copy a restrictive robots.txt to app-folder
 */
gulp.task('robots', function(){

  gulp.src([
      'src/root.htaccess'
    ])

    .pipe(prompt.prompt({
        type: 'input',
        name: 'h5bp',
        message: 'Do you want to lock out Web crawlers?',
        default: 'y'
    }, function(res){
        if(res.h5bp === 'y') {
              gulp.src(['src/robots.txt'])
              .pipe(concat('robots.txt'))
              .pipe(gulp.dest('app/'))
        }
    }));
});

gulp.task('help', function() {

  console.log('\n' + meta.name + ' v' + meta.version)
  console.log('==================\n')
  console.log('Available tasks:')
  console.log('        help - this dialog')
  console.log('      apache - append H5BP Apache Server Config to default .htaccess')
  console.log('   bootstrap - specify default Bootstrap theme')
  console.log('       clean - delete app-folder')
  console.log(' fontawesome - include Font Awesome icons')
  console.log('        hljs - include Highlight.js')
  console.log('        init - create app-folder and copy required files')
  console.log('        lint - run tasks to lint all CSS, JavaScript and PHP files')
  console.log('        make - minify all CSS and JavaScript files')
  console.log('       merge - merge all CSS and JavaScript files')
  console.log('       reset - reset config.json to default')
  console.log('      search - include scripts for Search Box')
  console.log('       theme - specify default Highlighter.js style-sheet')
  console.log('     upgrade - upgrade all PHP files in app-folder')
  console.log('      viewer - include scripts for Viewer modal')
  console.log('\nFor further details visit the GitHub repository:')
  console.log('https://github.com/idleberg/Bootstrap-Listr\n')

} )<commit_msg>added alias for make task<commit_after>var meta = require('./package.json');

var del     = require('del');
var concat    = require('gulp-concat');
var csslint   = require('gulp-csslint');
var cssmin    = require('gulp-cssmin');
var download  = require('gulp-download');
var gulp      = require('gulp');
var jshint    = require('gulp-jshint');
var jeditor   = require('gulp-json-editor');
var phplint   = require('phplint');
var prompt    = require('gulp-prompt');
var uglify    = require('gulp-uglify');

/*
 * Task combos
 */
gulp.task('lint',   ['csslint', 'jshint', 'phplint']);
gulp.task('make',   ['cssmin', 'uglify']);
gulp.task('travis', ['csslint', 'jshint']);

// Task aliases
gulp.task('bs',          ['bootstrap']);
gulp.task('css',         ['csslint', 'cssmin']);
gulp.task('fa',          ['icons']);
gulp.task('fontawesome', ['icons']);
gulp.task('highlighter', ['hljs']);
gulp.task('js',          ['jshint', 'uglify']);
gulp.task('minify',      ['make']);
gulp.task('php',         ['phplint']);
gulp.task('theme',       ['hljs_theme']);
gulp.task('update',      ['upgrade']);

/*
 * SELF COPY
 *
 * Create file structure in app/, copy all PHP & .htaccess
 */
gulp.task('init', function() {

  gulp.src([
      'src/index.php',
      'src/listr-functions.php',
      'src/listr-l10n.php',
      'src/listr-template.php'
    ])
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/locale/**/*'
    ])
    .pipe(gulp.dest('app/locale/'));

  gulp.src([
      'src/config.json'
    ])
    .pipe(concat('config.json'))
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/root.htaccess'
    ])
    .pipe(concat('.htaccess'))
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/public.htaccess'
    ])
    .pipe(concat('.htaccess'))
    .pipe(gulp.dest('app/_public/'));
});

/*
 * UPGRADE
 *
 * Upgrade files in app/. Does not touch config.json and .htaccess files!
 */
gulp.task('upgrade', function() {

  del([
    'app/assets/css/listr.pack.css',
    'app/assets/js/listr.pack.js'
  ])

  gulp.src([
      'src/index.php',
      'src/listr-functions.php',
      'src/listr-l10n.php',
      'src/listr-template.php'
    ])
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/root.htaccess'
    ])
    .pipe(concat('.htaccess-example'))
    .pipe(gulp.dest('app/'));

  gulp.src([
      'src/locale/**/*'
    ])
    .pipe(gulp.dest('app/locale/'));
});

/*
 * CLEAN-UP
 *
 * Delete all files in app
 */
gulp.task('clean', function () {
  return del(['app/']);
});

gulp.task('reset', function () {
  gulp.src([
      'src/config.json'
    ])
    .pipe(gulp.dest('app/'));
});

/*
 * LINT PHP
 */
gulp.task('phplint', function () {
  return phplint([
        'src/*.php'
    ]);
});

/*
 * LINT CSS
 */
gulp.task('csslint', function() {
  gulp.src([
      'src/style.css'
    ])
    .pipe(csslint())
    .pipe(csslint.reporter())
});

/*
 * MINIFY CSS
 */
gulp.task('cssmin', function() {
  gulp.src([
      'src/style.css'
    ])
    .pipe(concat('listr.min.css'))
    .pipe(cssmin())
    .pipe(gulp.dest('app/assets/css/'))
});

/*
 * HINT JS
 */
gulp.task('jshint', function() {
  gulp.src([
      'src/config.json',
      'src/scripts.js'
    ])
    .pipe(jshint())
    .pipe(jshint.reporter())
});

/*
 * UGLIFY JS
 */
gulp.task('uglify', function() {
  gulp.src([
      'src/scripts.js'
    ])
    .pipe(uglify())
    .pipe(concat('listr.min.js'))
    .pipe(gulp.dest('app/assets/js/'))
});

/*
 * MERGE ASSETS
 */

gulp.task('post_merge', function() {
  del([
    'app/assets/css/*.css',
    '!app/assets/css/listr.pack.css',
    'app/assets/js/*.js',
    '!app/assets/js/jquery.min.js',
    '!app/assets/js/listr.pack.js'
  ])
});

gulp.task('merge', function(){

  gulp.src([
      'app/assets'
    ])

    .pipe(prompt.prompt({
        type: 'input',
        name: 'merge',
        message: 'Do you want to merge all assets?',
        default: 'y'
    }, function(res){
        if(res.merge === 'y') {
              gulp.src([
                  'app/assets/css/*.css',
                  '!app/assets/css/listr.pack.css'
                ])
                .pipe(concat('listr.pack.css'))
                .pipe(gulp.dest('app/assets/css/')),

                gulp.src([
                  'app/assets/js/*.js',
                  '!app/assets/js/jquery.min.js',
                  '!app/assets/js/listr.pack.js'
                ])
                .pipe(concat('listr.pack.js'))
                .pipe(gulp.dest('app/assets/js/'));

                gulp.src("app/config.json")
                .pipe(jeditor({
                  'general': {
                    'dependencies': "pack"
                  }
                }))
                .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * BOOTSTRAP THEME SETUP
 *
 * Pick a Bootstrap theme
 */
gulp.task('bootstrap', function(){

 var bootswatch = ['default','amelia','cerulean','cosmo','cyborg','darkly','flatly','journal','lumen','paper','readable','sandstone','simplex','slate','spacelab','superhero','united','yeti'];

 gulp.src('.')
    .pipe(prompt.prompt({
        type: 'input',
        name: 'bootstrap',
        message: 'Which Bootstrap theme would you like to use?',
        default: 'default',
        validate: function(pass){

            if (bootswatch.indexOf(pass) == -1 ) {
                return false;
            }

            return true;
        }
    }, function(res){

        if(res.bootstrap === 'default') {
              gulp.src('node_modules/bootstrap/dist/css/bootstrap.min.css')
              .pipe(concat('bootstrap.min.css'))
              .pipe(gulp.dest('app/assets/css/'))
              gulp.src("app/config.json")
                .pipe(jeditor({
                  'bootstrap': {
                    'theme': 'default'
                  }
                }))
                .pipe(gulp.dest("app/"));
        } else if (bootswatch.indexOf(res.bootstrap) != -1 ) {
              gulp.src('node_modules/bootswatch/' + res.bootstrap + '/bootstrap.min.css')
              .pipe(concat('bootstrap.min.css'))
              .pipe(gulp.dest('app/assets/css/')),

              gulp.src("app/config.json")
              .pipe(jeditor({
                'bootstrap': {
                  'theme': res.bootstrap
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));

  gulp.src([
  'node_modules/bootstrap/fonts/*'

  ])
  .pipe(gulp.dest('app/assets/fonts/'));

});

/*
 * VIEWER SETUP
 *
 * Copy dependencies for the viewer modal
 */
gulp.task('viewer', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'viewer',
        message: 'Do you want to make use of the viewer modal?',
        default: 'y'
    }, function(res){
        if(res.viewer === 'y') {
              gulp.src([
                'node_modules/bootstrap/dist/js/bootstrap.min.js',
                'node_modules/jquery/dist/jquery.min.js',
                'node_modules/jquery/dist/jquery.min.map'
              ])
              .pipe(gulp.dest('app/assets/js/'));

              gulp.src("app/config.json")
              .pipe(jeditor({
                'general': {
                  'enable_viewer': true
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * SEARCH BOX SETUP
 *
 * Copy dependencies for the search box
 */
gulp.task('search', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'search',
        message: 'Do you want to make use of the search box?',
        default: 'y'
    }, function(res){
        if(res.search === 'y') {
              gulp.src([
                'node_modules/jquery/dist/jquery.min.js',
                'node_modules/jquery/dist/jquery.min.map',
                'node_modules/jquery-searcher/dist/jquery.searcher.min.js'

              ])
              .pipe(gulp.dest('app/assets/js/'))

              gulp.src("app/config.json")
              .pipe(jeditor({
                'general': {
                  'enable_search': true
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * FONT AWESOME SETUP
 *
 * Copy dependencies for Font Awesome icons
 */
gulp.task('icons', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'fontawesome',
        message: 'Do you want to make use of Font Awesome icons?',
        default: 'y'
    }, function(res){
        if(res.fontawesome === 'y') {

              gulp.src([
                'node_modules/font-awesome/css/font-awesome.min.css'

              ])
              .pipe(gulp.dest('app/assets/css/'))

              gulp.src([
                'node_modules/font-awesome/fonts/*'

              ])
              .pipe(gulp.dest('app/assets/fonts/'))

              gulp.src("app/config.json")
              .pipe(jeditor({
                'bootstrap': {
                  'icons': 'fontawesome'
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * HIGHLIGHT.JS SETUP
 *
 * Copy dependencies for the syntax highlighter
 */
gulp.task('hljs', function(){

  gulp.src('.')

    .pipe(prompt.prompt({
        type: 'input',
        name: 'hljs',
        message: 'Do you want to make use of the syntax highlighter?',
        default: 'n'
    }, function(res){
        if(res.hljs === 'y') {
              download('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/highlight.min.js')
              .pipe(gulp.dest('app/assets/js/'))

              gulp.src("app/config.json")
              .pipe(jeditor({
                'general': {
                  'enable_highlight': true
                }
              }))
              .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * HIGHLIGHT.JS THEME
 *
 * Pick a style-sheet for Highlight.js
 */
gulp.task('hljs_theme', function(){

 var hljs_theme = ['arta', 'ascetic', 'atelier-dune.dark', 'atelier-dune.light', 'atelier-forest.dark', 'atelier-forest.light', 'atelier-heath.dark', 'atelier-heath.light', 'atelier-lakeside.dark', 'atelier-lakeside.light', 'atelier-seaside.dark', 'atelier-seaside.light', 'brown_paper', 'dark', 'default', 'docco', 'far', 'foundation', 'github', 'googlecode', 'idea', 'ir_black', 'magula', 'mono-blue', 'monokai', 'monokai_sublime', 'obsidian', 'paraiso.dark', 'paraiso.light', 'pojoaque', 'railscasts', 'rainbow', 'school_book', 'solarized_dark', 'solarized_light', 'sunburst', 'tomorrow-night-blue', 'tomorrow-night-bright', 'tomorrow-night-eighties', 'tomorrow-night', 'tomorrow', 'vs', 'xcode', 'zenburn']

 gulp.src('.')
    .pipe(prompt.prompt({
        type: 'input',
        name: 'highlighter',
        message: 'Which Highlight.js theme would you like to use?',
        default: 'github',
        validate: function(pass){

            if (hljs_theme.indexOf(pass) == -1 ) {
                return false;
            }

            return true;
        }
    }, function(res){

        if (hljs_theme.indexOf(res.highlighter) != -1) {
          download('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/styles/' + res.highlighter + '.min.css')

          .pipe(concat('highlight.min.css'))
          .pipe(gulp.dest('app/assets/css/'));

          gulp.src("app/config.json")
          .pipe(jeditor({
            'highlight': {
              'theme': res.hljs_theme
            }
          }))
          .pipe(gulp.dest("app/"));
        }
    }));
});

/*
 * APACHE SERVER CONFIGS
 *
 * Append HTML5 Boilerplate's Apache rules to .htaccess
 */
gulp.task('apache', function(){

  gulp.src([
      'src/root.htaccess'
    ])

    .pipe(prompt.prompt({
        type: 'input',
        name: 'h5bp',
        message: 'Do you want to append H5BP\'s Apache Server Config rules?',
        default: 'y'
    }, function(res){
        if(res.h5bp === 'y') {
              gulp.src(['src/root.htaccess','node_modules/apache-server-configs/dist/.htaccess'])
              .pipe(concat('.htaccess'))
              .pipe(gulp.dest('app/'))
        }
    }));
});

/*
 * ROBOTS
 *
 * Copy a restrictive robots.txt to app-folder
 */
gulp.task('robots', function(){

  gulp.src([
      'src/root.htaccess'
    ])

    .pipe(prompt.prompt({
        type: 'input',
        name: 'h5bp',
        message: 'Do you want to lock out Web crawlers?',
        default: 'y'
    }, function(res){
        if(res.h5bp === 'y') {
              gulp.src(['src/robots.txt'])
              .pipe(concat('robots.txt'))
              .pipe(gulp.dest('app/'))
        }
    }));
});

gulp.task('help', function() {

  console.log('\n' + meta.name + ' v' + meta.version)
  console.log('==================\n')
  console.log('Available tasks:')
  console.log('        help - this dialog')
  console.log('      apache - append H5BP Apache Server Config to default .htaccess')
  console.log('   bootstrap - specify default Bootstrap theme')
  console.log('       clean - delete app-folder')
  console.log(' fontawesome - include Font Awesome icons')
  console.log('        hljs - include Highlight.js')
  console.log('        init - create app-folder and copy required files')
  console.log('        lint - run tasks to lint all CSS, JavaScript and PHP files')
  console.log('        make - minify all CSS and JavaScript files')
  console.log('       merge - merge all CSS and JavaScript files')
  console.log('       reset - reset config.json to default')
  console.log('      search - include scripts for Search Box')
  console.log('       theme - specify default Highlighter.js style-sheet')
  console.log('     upgrade - upgrade all PHP files in app-folder')
  console.log('      viewer - include scripts for Viewer modal')
  console.log('\nFor further details visit the GitHub repository:')
  console.log('https://github.com/idleberg/Bootstrap-Listr\n')

} )<|endoftext|>


<commit_before>var messages = require('../messages.json')
var debug = require('debug')('TEST')
var Github = require('github-api')
var request = require('request')
var tape = require('tape')

var github = new Github({
  auth: 'oauth',
  token: process.env['REPOROBOT_TOKEN']
})

var reqHeaders = {
  'User-Agent': 'request',
  'Authorization': 'token ' + process.env['REPOROBOT_TOKEN']
}

var fork = github.getRepo('reporobot', 'patchwork')
var upstream = github.getRepo('jlord', 'patchwork')
var baseURL = 'https://api.github.com/repos/'
var prnum

// Create a branch on RR's fork of Patchwork. Then create a file on that
// branch so that you can create a PR. Check to see if RR commented on that PR.
// Delete branch when finished (or have failed).

tape("Test a correct PR", function(t) {

  createBranch()

  function createBranch() {
    debug("⬢ Creating branch")
    fork.branch('gh-pages', 'add-reporobot', function(err) {
      if (err) {
        t.error(err, "Error creating branch on RRs fork")
        return t.end()
      }
      setTimeout(createDiff(), 5000)
    })
  }

  function createDiff() {
    var options = {
      headers: reqHeaders,
      url: baseURL + "reporobot/patchwork/contents/contributors/add-reporobot.txt",
      json: true,
      body: {
        "path": "contributors/add-reporobot.txt",
        "branch": "add-reporobot",
        "message": "TEST",
        "content": "bXkgbmV3IGZpbGUgY29udGVudHM=",
        "committer": {
          "name": "reporobot",
          "email": "60ebe73fdad8ee59d45c@cloudmailin.net"
        }
      }
    }

    request.put(options, function(err, res, body) {
      debug("⬢ Creating diff")
      if (err) {
        t.error(err, "Error making new file on branch", body)
        return t.end()
      }
      // Give GitHub some time
      setTimeout(function() { makePR() }, 5000)
    })
  }

  function makePR() {
    debug("⬢ Creating PR")
    var pull = {
      title: "[TESTING] Correct PR",
      body: "Running a test on a correct PR",
      base: "gh-pages",
      head: "reporobot:" + "add-reporobot"
    }

    upstream.createPullRequest(pull, function(err, pr) {
      if (err) {
        t.error(err, "error creating PR")
        return t.end()
      }
      prnum = pr.number
      // Give RR time to respond to PR
      setTimeout(function() { fetchPR(res,body) }, 15000)
    })
  }

  function fetchPR() {
    debug("⬢ Fetching PR")
    var prURL = baseURL + 'jlord/patchwork/issues/' + prnum
    var options = { headers: reqHeaders, json: true, url: prURL }

    request(options, function(err, res, body) {
      if (err) {
        t.error(err, "error fetching PR")
        return t.end()
      }
      if (res.length === 0) {
        t.fail("No PR created")
        return t.end()
      }
      checkClosed(res, body)
    })
  }

  function checkClosed(res, body) {
    debug("⬢ Getting comment")
    console.log(body)
  }
})

// TODO tear down @reporobot in /patchworks
// rebuild /patchwork

// tape("Test cleanup", function(t) {
//
//   deleteViaBranch()
//
//   function deleteViaBranch() {
//     debug("⬢ Deleting branch")
//     fork.deleteRef('heads/add-reporobot', function(err) {
//       if (err && err.error != '422') {
//         t.error(err, "Error deleting branch")
//         return t.end()
//       }
//       debug("⬢ Branch deleted on RR fork.")
//       t.end()
//     })
//   }
// })
<commit_msg>notes, start prep for rebuilding page<commit_after>var rebuildpage = require('./buildpage.js')
var messages = require('../messages.json')
var debug = require('debug')('TEST')
var Github = require('github-api')
var request = require('request')
var tape = require('tape')

var github = new Github({
  auth: 'oauth',
  token: process.env['REPOROBOT_TOKEN']
})

var reqHeaders = {
  'User-Agent': 'request',
  'Authorization': 'token ' + process.env['REPOROBOT_TOKEN']
}

var fork = github.getRepo('reporobot', 'patchwork')
var upstream = github.getRepo('jlord', 'patchwork')
var baseURL = 'https://api.github.com/repos/'
var prnum

// Create a branch on RR's fork of Patchwork. Then create a file on that
// branch so that you can create a PR. Check to see if RR commented on that PR.
// Delete branch when finished (or have failed).

tape("Test a correct PR", function(t) {

  createBranch()

  function createBranch() {
    debug("⬢ Creating branch")
    fork.branch('gh-pages', 'add-reporobot', function(err) {
      if (err) {
        t.error(err, "Error creating branch on RRs fork")
        return t.end()
      }
      setTimeout(createDiff(), 5000)
    })
  }

  function createDiff() {
    var options = {
      headers: reqHeaders,
      url: baseURL + "reporobot/patchwork/contents/contributors/add-reporobot.txt",
      json: true,
      body: {
        "path": "contributors/add-reporobot.txt",
        "branch": "add-reporobot",
        "message": "TEST",
        "content": "bXkgbmV3IGZpbGUgY29udGVudHM=",
        "committer": {
          "name": "reporobot",
          "email": "60ebe73fdad8ee59d45c@cloudmailin.net"
        }
      }
    }

    request.put(options, function(err, res, body) {
      debug("⬢ Creating diff")
      if (err) {
        t.error(err, "Error making new file on branch", body)
        return t.end()
      }
      // Give GitHub some time
      setTimeout(function() { makePR() }, 5000)
    })
  }

  function makePR() {
    debug("⬢ Creating PR")
    var pull = {
      title: "[TESTING] Correct PR",
      body: "Running a test on a correct PR",
      base: "gh-pages",
      head: "reporobot:" + "add-reporobot"
    }

    upstream.createPullRequest(pull, function(err, pr) {
      if (err) {
        t.error(err, "error creating PR")
        return t.end()
      }
      prnum = pr.number
      // Give RR time to respond to PR
      setTimeout(function() { fetchPR(res,body) }, 15000)
    })
  }

  function fetchPR() {
    debug("⬢ Fetching PR")
    var prURL = baseURL + 'jlord/patchwork/issues/' + prnum
    var options = { headers: reqHeaders, json: true, url: prURL }

    request(options, function(err, res, body) {
      if (err) {
        t.error(err, "error fetching PR")
        return t.end()
      }
      if (res.length === 0) {
        t.fail("No PR created")
        return t.end()
      }
      checkClosed(res, body)
    })
  }

  function checkClosed(res, body) {
    debug("⬢ Getting comment")
    console.log(body)
    // did the pr get merged?
  }
})

// TODO tear down @reporobot in /patchworks
// rebuild /patchwork

// get contributors.json file from upstream
// parse it and delete RR as last entry
// or check the last five entries to be RR
// rebuild page based
// push the edited file back upstream
//

// tape("Test cleanup", function(t) {
//
//   deleteViaBranch()
//
//   function deleteViaBranch() {
//     debug("⬢ Deleting branch")
//     fork.deleteRef('heads/add-reporobot', function(err) {
//       if (err && err.error != '422') {
//         t.error(err, "Error deleting branch")
//         return t.end()
//       }
//       debug("⬢ Branch deleted on RR fork.")
//       t.end()
//     })
//   }
// })
<|endoftext|>


<commit_before>function Simulation(id, delayFactory) {
   this.stepIndex = 0;
   this.steps = [];
   this.autoPlaying = false;
   this.playing = false;
   this.stopping = false;

   this.addStep = function(step) {
      var that = this;

      step.addEntryAllParents({
         name: "simulation$$$",
         action: {
            onExec: function(params, duration, callback) {
               that.playing = false;
               that.stepIndex++;
               if (that.autoPlaying) {
                  if (that.stepIndex < that.steps.length && !(that.stopping)) {
                     that.play();
                  }
               }
               callback();
            }
         }
      });

      this.steps.push(step);
   };

   this.addStepWithEntry = function(entry) {
      var step = new SimulationStep();
      step.addEntry(entry);
      this.addStep(step);
   };

   this.getLastStep = function() {
      return this.steps[this.steps.length - 1];
   };

   this.setAutoPlay = function(autoPlay) {
      this.autoPlaying = autoPlay;
   };

   this.play = function() {
      this.playing = true;
      this.steps[this.stepIndex].setExpedite(this.expediting);
      this.steps[this.stepIndex].execute(delayFactory);
   };

   this.stop = function() {
      if (this.playing) {
         this.stopping = true;
         this.playing = false;
         this.steps[this.stepIndex].stop();
         this.stopping = false;
      }
   };

   this.playNext = function() {
      this.stepIndex++;
      this.play();
   };

   this.gotoAndPlay = function(stepIndex) {
      this.stepIndex = stepIndex;
      this.play();
   };

   this.gotoAndStop = function(stepIndex) {
      this.stop();
      this.stepIndex = stepIndex;
   };

   this.canPlay = function() {
      return this.steps && this.stepIndex < this.steps.length;
   };

   this.isPlaying = function() {
      return this.playing;
   };

   this.gotoLastStep = function() {
      this.stepIndex = this.steps.length - 1;
   };

   this.setExpedite = function(expedite) {
      if(!expedite) {
         this.expediting = false;
         return;
      }
      if(this.expediting) {
         return;
      }

      this.expediting = true;

      if(this.steps.length > this.stepIndex) {
         this.steps[this.stepIndex].setExpedite(true);
      }
   };

   this.isOnLastStep = function() {
      return this.stepIndex === this.steps.length - 1;
   };

   this.clear = function() {
      this.stop();
      this.steps = [];
      this.stepIndex = 0;
   };
}

function SimulationStep() {
   this.entries = {};
   this.stopping = false;

   this.addEntry = function(entry) {
      this.entries[entry.name] = entry;
   };

   this.addEntries = function(entries) {
      for(var name in entries) {
         this.addEntry(entries[name]);
      }
   };

   this.addEntryAllParents = function(entry) {
      if (!(entry.parents)) {
         entry.parents = [];
      }
      for (var name in this.entries) {
         entry.parents.push(name);
      }
      this.addEntry(entry);
   };

   this.addEntriesAllParents = function(newEntries) {
      var newName;
      for (newName in newEntries) {
         var newEntry = newEntries[newName];
         if (!(newEntries.parents)) {
            newEntry.parents = [];
         }
         for (var name in this.entries) {
            newEntry.parents.push(name);
         }
      }
      for (newName in newEntries) {
         this.addEntry(newEntries[newName]);
      }
   };

   this.resetParents = function() {
      var name;

      for (name in this.entries) {
         this.entries[name].parentsDone = 0;
         this.entries[name].children = [];
      }

      for (name in this.entries) {
         var parents = this.entries[name].parents;
         for (var iParent in parents) {
            this.entries[parents[iParent]].children.push(name);
         }
      }
   };

   this.execute = function(delayFactory) {
      this.resetParents();
      for (var name in this.entries) {
         if (!(this.entries[name].parents) || this.entries[name].parents.length === 0) {
            this.executeEntry(name, delayFactory);
         }
      }
   };

   this.executeEntry = function(name, delayFactory) {
      //console.log("Simulation: Executing entry: " + name);
      var entry = this.entries[name];
      var that = this;

      var onFinish = function() {
         //console.log("Simulation: Finished executing entry: " + name);
         //console.log("My stopping state is: " + that.stopping);
         for (var iChild in entry.children) {
            var childName = entry.children[iChild];
            var childEntry = that.entries[childName];
            childEntry.parentsDone++;

            if (childEntry.parentsDone == childEntry.parents.length && !(that.stopping)) {
               that.executeEntry(childName, delayFactory);
            }
         }
      };

      entry.runner = new SimulationEntryRunner(entry, delayFactory, onFinish);
      entry.runner.execute(this.expediting);
   };

   this.stop = function() {
      //console.log("Simulation: stopping");
      this.stopping = true;
      for (var name in this.entries) {
         //console.log("Simulation: stopping " + name);
         var entry = this.entries[name];
         if (entry.runner && entry.runner.executing) {
            entry.runner.stop();
            //console.log("Simulation: " + name + " stopped");
         }
      }
      this.stopping = false;
   };

   this.setExpedite = function(expedite) {
      this.expediting = expedite;
   };
}

function SimulationEntry(name, action, parents, delay) {

}

function SimulationAction(onExec, params, duration, useTimeout) {

}

var _simulationCallbackCounter = 0;

function SimulationEntryRunner(entry, delayFactory, callback) {
   var that = this;
   var _SIMULATION_TIMEOUT_PREFIX = "$simulation$";
   var _SIMULATION_TIMEOUT_DELAY_PREFIX = "$simulation-delay$";
   var _SIMULATION_CALLBACK_DELAY_PREFIX = "$simulation-callback$";
   this.name = entry.name;
   this.onExec = entry.action.onExec;
   this.params = entry.action.params;
   this.action = entry.action;
   this.duration = entry.action.duration;
   this.useTimeout = entry.action.useTimeout;
   this.delay = entry.delay;
   this.callback = callback;

   this.executing = false;

   this.execute = function(expedite){
      this.executing = true;
      var delay = this.delay;
      var duration = this.duration;
      if(expedite) {
         delay = 0;
         duration = 0;
      }

      var onDelayEnd = function() {
         //console.log("Entry: " + that.name + " delay is finished.");
         if (!(that.executing)) {
            return;
         }

         var onFinish = function() {
            //console.log("Entry: finishing " + that.name);
            that.sensitiveStop(expedite);
         };

         //console.log("Entry: registering animation for " + that.name);
         that.actingObject = that.onExec(that.params, duration, onFinish);
         if (that.useTimeout) {
            if(expedite || duration === 0) {
               onFinish();
            }
            else {
               //console.log("Entry: registering timeout for " + that.name);
               delayFactory.create(_SIMULATION_TIMEOUT_PREFIX + that.name, onFinish, duration);
            }
         }
      };

      if (delay) {
         delayFactory.create(_SIMULATION_TIMEOUT_DELAY_PREFIX + this.name, onDelayEnd, delay);
      } else {
         onDelayEnd();
      }
   };

   this.stop = function() {
      if (!(that.executing)) {
         return;
      }
      that.executing = false;
      delayFactory.destroy(_SIMULATION_TIMEOUT_PREFIX + that.name);
      delayFactory.destroy(_SIMULATION_TIMEOUT_DELAY_PREFIX + that.name);
      delayFactory.destroy(_SIMULATION_CALLBACK_DELAY_PREFIX + that.name);
      if (that.actingObject && that.actingObject.stop) {
         that.actingObject.stop();
      }
      that.actingObject = null;
      that.callback();
   };

   /*
    * Stop this entry, but if expediting is enabled,
    * use a timeout of 0 instead, every 100 times.
    * This prevents stack overflow in long simulations.
    */
   this.sensitiveStop = function(expedite) {
      if(!expedite) {
         this.stop();
         return;
      }

      _simulationCallbackCounter++;
      // console.log(_simulationCallbackCounter);
      if(_simulationCallbackCounter > 100) {
         _simulationCallbackCounter = 0;
         // console.log("stop with delay");
         delayFactory.create(_SIMULATION_CALLBACK_DELAY_PREFIX + this.name, this.stop, 0);
      }
      else {
         // console.log("stop without delay");
         this.stop();
      }
   };
}
<commit_msg>simulation-2.0.js: add id<commit_after>function Simulation(id, delayFactory) {
   this.id = id;
   this.stepIndex = 0;
   this.steps = [];
   this.autoPlaying = false;
   this.playing = false;
   this.stopping = false;

   this.addStep = function(step) {
      var that = this;

      step.addEntryAllParents({
         name: "simulation$$$",
         action: {
            onExec: function(params, duration, callback) {
               that.playing = false;
               that.stepIndex++;
               if (that.autoPlaying) {
                  if (that.stepIndex < that.steps.length && !(that.stopping)) {
                     that.play();
                  }
               }
               callback();
            }
         }
      });

      this.steps.push(step);
   };

   this.addStepWithEntry = function(entry) {
      var step = new SimulationStep();
      step.addEntry(entry);
      this.addStep(step);
   };

   this.getLastStep = function() {
      return this.steps[this.steps.length - 1];
   };

   this.setAutoPlay = function(autoPlay) {
      this.autoPlaying = autoPlay;
   };

   this.play = function() {
      this.playing = true;
      this.steps[this.stepIndex].setExpedite(this.expediting);
      this.steps[this.stepIndex].execute(delayFactory);
   };

   this.stop = function() {
      if (this.playing) {
         this.stopping = true;
         this.playing = false;
         this.steps[this.stepIndex].stop();
         this.stopping = false;
      }
   };

   this.playNext = function() {
      this.stepIndex++;
      this.play();
   };

   this.gotoAndPlay = function(stepIndex) {
      this.stepIndex = stepIndex;
      this.play();
   };

   this.gotoAndStop = function(stepIndex) {
      this.stop();
      this.stepIndex = stepIndex;
   };

   this.canPlay = function() {
      return this.steps && this.stepIndex < this.steps.length;
   };

   this.isPlaying = function() {
      return this.playing;
   };

   this.gotoLastStep = function() {
      this.stepIndex = this.steps.length - 1;
   };

   this.setExpedite = function(expedite) {
      if(!expedite) {
         this.expediting = false;
         return;
      }
      if(this.expediting) {
         return;
      }

      this.expediting = true;

      if(this.steps.length > this.stepIndex) {
         this.steps[this.stepIndex].setExpedite(true);
      }
   };

   this.isOnLastStep = function() {
      return this.stepIndex === this.steps.length - 1;
   };

   this.clear = function() {
      this.stop();
      this.steps = [];
      this.stepIndex = 0;
   };
}

function SimulationStep() {
   this.entries = {};
   this.stopping = false;

   this.addEntry = function(entry) {
      this.entries[entry.name] = entry;
   };

   this.addEntries = function(entries) {
      for(var name in entries) {
         this.addEntry(entries[name]);
      }
   };

   this.addEntryAllParents = function(entry) {
      if (!(entry.parents)) {
         entry.parents = [];
      }
      for (var name in this.entries) {
         entry.parents.push(name);
      }
      this.addEntry(entry);
   };

   this.addEntriesAllParents = function(newEntries) {
      var newName;
      for (newName in newEntries) {
         var newEntry = newEntries[newName];
         if (!(newEntries.parents)) {
            newEntry.parents = [];
         }
         for (var name in this.entries) {
            newEntry.parents.push(name);
         }
      }
      for (newName in newEntries) {
         this.addEntry(newEntries[newName]);
      }
   };

   this.resetParents = function() {
      var name;

      for (name in this.entries) {
         this.entries[name].parentsDone = 0;
         this.entries[name].children = [];
      }

      for (name in this.entries) {
         var parents = this.entries[name].parents;
         for (var iParent in parents) {
            this.entries[parents[iParent]].children.push(name);
         }
      }
   };

   this.execute = function(delayFactory) {
      this.resetParents();
      for (var name in this.entries) {
         if (!(this.entries[name].parents) || this.entries[name].parents.length === 0) {
            this.executeEntry(name, delayFactory);
         }
      }
   };

   this.executeEntry = function(name, delayFactory) {
      //console.log("Simulation: Executing entry: " + name);
      var entry = this.entries[name];
      var that = this;

      var onFinish = function() {
         //console.log("Simulation: Finished executing entry: " + name);
         //console.log("My stopping state is: " + that.stopping);
         for (var iChild in entry.children) {
            var childName = entry.children[iChild];
            var childEntry = that.entries[childName];
            childEntry.parentsDone++;

            if (childEntry.parentsDone == childEntry.parents.length && !(that.stopping)) {
               that.executeEntry(childName, delayFactory);
            }
         }
      };

      entry.runner = new SimulationEntryRunner(entry, delayFactory, onFinish);
      entry.runner.execute(this.expediting);
   };

   this.stop = function() {
      //console.log("Simulation: stopping");
      this.stopping = true;
      for (var name in this.entries) {
         //console.log("Simulation: stopping " + name);
         var entry = this.entries[name];
         if (entry.runner && entry.runner.executing) {
            entry.runner.stop();
            //console.log("Simulation: " + name + " stopped");
         }
      }
      this.stopping = false;
   };

   this.setExpedite = function(expedite) {
      this.expediting = expedite;
   };
}

function SimulationEntry(name, action, parents, delay) {

}

function SimulationAction(onExec, params, duration, useTimeout) {

}

var _simulationCallbackCounter = 0;

function SimulationEntryRunner(entry, delayFactory, callback) {
   var that = this;
   var _SIMULATION_TIMEOUT_PREFIX = "$simulation$";
   var _SIMULATION_TIMEOUT_DELAY_PREFIX = "$simulation-delay$";
   var _SIMULATION_CALLBACK_DELAY_PREFIX = "$simulation-callback$";
   this.name = entry.name;
   this.onExec = entry.action.onExec;
   this.params = entry.action.params;
   this.action = entry.action;
   this.duration = entry.action.duration;
   this.useTimeout = entry.action.useTimeout;
   this.delay = entry.delay;
   this.callback = callback;

   this.executing = false;

   this.execute = function(expedite){
      this.executing = true;
      var delay = this.delay;
      var duration = this.duration;
      if(expedite) {
         delay = 0;
         duration = 0;
      }

      var onDelayEnd = function() {
         //console.log("Entry: " + that.name + " delay is finished.");
         if (!(that.executing)) {
            return;
         }

         var onFinish = function() {
            //console.log("Entry: finishing " + that.name);
            that.sensitiveStop(expedite);
         };

         //console.log("Entry: registering animation for " + that.name);
         that.actingObject = that.onExec(that.params, duration, onFinish);
         if (that.useTimeout) {
            if(expedite || duration === 0) {
               onFinish();
            }
            else {
               //console.log("Entry: registering timeout for " + that.name);
               delayFactory.create(_SIMULATION_TIMEOUT_PREFIX + that.name, onFinish, duration);
            }
         }
      };

      if (delay) {
         delayFactory.create(_SIMULATION_TIMEOUT_DELAY_PREFIX + this.name, onDelayEnd, delay);
      } else {
         onDelayEnd();
      }
   };

   this.stop = function() {
      if (!(that.executing)) {
         return;
      }
      that.executing = false;
      delayFactory.destroy(_SIMULATION_TIMEOUT_PREFIX + that.name);
      delayFactory.destroy(_SIMULATION_TIMEOUT_DELAY_PREFIX + that.name);
      delayFactory.destroy(_SIMULATION_CALLBACK_DELAY_PREFIX + that.name);
      if (that.actingObject && that.actingObject.stop) {
         that.actingObject.stop();
      }
      that.actingObject = null;
      that.callback();
   };

   /*
    * Stop this entry, but if expediting is enabled,
    * use a timeout of 0 instead, every 100 times.
    * This prevents stack overflow in long simulations.
    */
   this.sensitiveStop = function(expedite) {
      if(!expedite) {
         this.stop();
         return;
      }

      _simulationCallbackCounter++;
      // console.log(_simulationCallbackCounter);
      if(_simulationCallbackCounter > 100) {
         _simulationCallbackCounter = 0;
         // console.log("stop with delay");
         delayFactory.create(_SIMULATION_CALLBACK_DELAY_PREFIX + this.name, this.stop, 0);
      }
      else {
         // console.log("stop without delay");
         this.stop();
      }
   };
}
<|endoftext|>