<commit_before>var fs          = require('fs'),
		_           = require('underscore'),
		Client      = require('pg').Client;

// TODO
// Only print `query` during .each on the first row, else print `''`
// Maybe print query in verbose mode or something to make syntax nicer on callback
// Put some defaults for finding where your pg server is located, default to postgres@localhost/butter_knife, then postgres@localhost/
// A method for just just inserting a file into postgres through node and through command line, temp table and not temp table.
// Allow for option that creates a non temp table, and drops each time
// Test date type
// Make `bk.queries` example

var client,
		tables = [],
		conString = fs.readFileSync(__dirname + '/db_config.txt').toString(),
		err_preview_length = 100,
		table_type = 'TEMP ',
		connected = false;

var helpers = {
	sqlizeType: function(value, key, data, i){
		var err;
		if (_.isString(value)){
			return 'text'
		} else if (_.isNumber(value)){
			return 'integer'
		} else if (_.isArray(value)){
				if (_.isObject(value[0])) { return 'json'   }    // If the array's first child is an object, assume that it's an array of objects and thus json.
				if (_.isArray( value[0])) { return 'text[]' }    // If it's text, then assume it's a list of strings.
				if (_.isNumber(value[0])) { return 'integer[]' } // If it's a number then integers
				if (_.isDate(  value[0])) { return 'date[]' }    // If date then dates. Unclear if this works
		} else if (_.isBoolean(value)){
			return 'boolean'
		} else if (_.isObject(value)){
			return 'json'
		} else if (_.isDate(value)){
			return 'date'
		} else if ((_.isNull(value) || _.isUndefined(value)) ){
			if (i < data.length - 1 ){ return null } // If it's not the last row then continue processing other rows. Else...
			err = 'Your column "' + key + '" doesn\'t contain any values. Please include a value in at least one row. Or, manually define your schema instead.';
			throw err + '\n{ ' + key + ': ' + value + ' }';
		}
	},
	describeColumn: function(columns, data, i){
		_.each(data[i], function(value, key){
			if (!columns[key]){
				columns[key] = helpers.sqlizeType(value, key, data, i)
			}
		})
		return columns
	},
	describeColumns: function(data){
		var columns = {},
				i = 0;
		this.describeColumn(columns, data, i)
		// If there are null values for that object, then try the next object
		while (_.values(columns).indexOf(null) != -1){
			i++
			this.describeColumn(columns, data, i)
		}
		return columns
	},
	columnTypesToString: function(data){
		var columns = this.describeColumns(data),
				column_types = [];
		_.each(columns, function(value, key){
			column_types.push(key + ' ' + value)
		})
		return column_types.join(',')
	},
	prepValuesForInsert: function(holder, data_row, quote_char){
		var arr_holder; // In case your value is an array, run this function recursively to properly quote its values.
		if (!quote_char) {quote_char = '$$'}
		_.values(data_row).forEach(function(value){
			if (_.isString(value)){
				holder.push(quote_char + value + quote_char)
			} else if (_.isUndefined(value) || _.isNull(value) || _.isNaN(value)){
				holder.push('NULL')
			} else if (_.isNumber(value)){
				holder.push(value)
			} else if (_.isArray(value)){
				arr_holder = [];
				arr_holder = helpers.prepValuesForInsert(arr_holder, value, '"');
				holder.push(quote_char + "{" + arr_holder + "}" + quote_char);
			} else if (_.isObject(value)){
				holder.push(quote_char + JSON.stringify(value) + quote_char)
			} else if (_.isBoolean){
				holder.push(value)
			} else {
				console.log('ERROR uncaught datatype', value, 'is', typeof value)
			} // Insert date support here.
		})
		return holder.join(',');
	},
	assembleValueInsertString: function(table_name, data){
	  var stmt ='INSERT INTO ' + table_name + ' (' + _.keys(data[0]).join(',') + ') VALUES ',
	      val_arr = [];
		for (var i = 0; i < data.length; i++){
			val_arr.push('(' + helpers.prepValuesForInsert([], data[i]) + ')');
		}
		stmt += val_arr.join(',');
		return stmt;
	},
	handleErr: function(err, msg, qt){
		var pos,
				err_text = 'Error in ' + msg;
		if (err){
			pos = Number(err.position);
			if (qt) {err_text += ':\n' + qt.substr(Math.max(0, pos - err_preview_length), Math.min(pos, err_preview_length)) + '^' + qt.substr(pos, Math.min(qt.length - pos, err_preview_length)) + '\n\n'} // Display the area where the query threw an error marked by a `^`. If the error occurs within the first fifty characters, make it start at the beginning of the string.
			console.error(err_text, err)
			throw err
		}
	}
}

function connectToDb(connection_string){
	connection_string = connection_string || conString;
	client = client || new Client(connection_string);
  client.on('drain', client.end.bind(client)); //disconnect client when all queries are finished
	client.connect(function(err){
  	helpers.handleErr(err, 'database connection');
	});
	connected = true;
}

function createTableCommands(table_name, table_data, table_schema){
	var table_commands = {};
	table_commands.create = 'CREATE ' + table_type + 'TABLE ' + table_name + ' (uid BIGSERIAL PRIMARY KEY,' + ((table_schema) ? table_schema : helpers.columnTypesToString(table_data)) + ')';
	table_commands.insert = helpers.assembleValueInsertString(table_name, table_data);
	return table_commands;
}

function createAndInsert(table_commands){
	client.query(table_commands.create, function(err, result){
  	helpers.handleErr(err, 'table creation', table_commands.create)
	});
  client.query(table_commands.insert, function(err, result){
  	helpers.handleErr(err, 'row insertion', table_commands.insert)
  });
}

function createTable(table_name, table_data, table_schema){
	if (!connected) connectToDb();
	var table_commands = createTableCommands(table_name, table_data, table_schema);
	createAndInsert(table_commands);
}

function query(query_text, cb){
	var result_obj = {}
  client.query(query_text, function(err, result){
  	helpers.handleErr(err, 'query', query_text)
  	result_obj.query = query_text;
  	result_obj.rows  = result.rows
  	cb(result_obj);
  })
}
function queries(query_texts, cb){
	var results = [],
			counter = 0;

	for (var i = 0; i < query_texts.length; i++){
		(function(query_text){
			var result_obj = {};
		  client.query(query_text, function(err, result){
		  	counter++;
		  	helpers.handleErr(err, 'query', query_text)
		  	result_obj.query = query_text;
		  	result_obj.rows = result.rows;
		  	results.push(result_obj);
		  	if (counter == query_texts.length){
			  	cb(results);
		  	}
		  })
		})(query_texts[i])

	}
}
query.each = function(query_text, cb){
	var query = client.query(query_text);
  query.on('row', function(row, result){
  	cb(row, query_text);
  })
}

module.exports = {
	createTable: createTable,
	query: query,
	queries: queries,
	createTableCommands: createTableCommands,
	connect: function(connection_string){
		connectToDb(connection_string);
		return this;
	},
	errLength: function(length){
		err_preview_length = length;
		return this
	},
	temp: function(type){
		if (!type) table_type = '';
		return this
	}
}

<commit_msg>change default number datatype to numeric to handle decimels<commit_after>var fs          = require('fs'),
		_           = require('underscore'),
		Client      = require('pg').Client;

// TODO
// Only print `query` during .each on the first row, else print `''`
// Maybe print query in verbose mode or something to make syntax nicer on callback
// Put some defaults for finding where your pg server is located, default to postgres@localhost/butter_knife, then postgres@localhost/
// A method for just just inserting a file into postgres through node and through command line, temp table and not temp table.
// Allow for option that creates a non temp table, and drops each time
// Test date type
// Make `bk.queries` example

var client,
		tables = [],
		conString = fs.readFileSync(__dirname + '/db_config.txt').toString(),
		err_preview_length = 100,
		table_type = 'TEMP ',
		connected = false;

var helpers = {
	sqlizeType: function(value, key, data, i){
		var err;
		if (_.isString(value)){
			return 'text'
		} else if (_.isNumber(value)){
			return 'numeric'
		} else if (_.isArray(value)){
				if (_.isObject(value[0])) { return 'json'   }    // If the array's first child is an object, assume that it's an array of objects and thus json.
				if (_.isArray( value[0])) { return 'text[]' }    // If it's text, then assume it's a list of strings.
				if (_.isNumber(value[0])) { return 'numeric[]' } // If it's a number then integers
				if (_.isDate(  value[0])) { return 'date[]' }    // If date then dates. Unclear if this works
		} else if (_.isBoolean(value)){
			return 'boolean'
		} else if (_.isObject(value)){
			return 'json'
		} else if (_.isDate(value)){
			return 'date'
		} else if ((_.isNull(value) || _.isUndefined(value)) ){
			if (i < data.length - 1 ){ return null } // If it's not the last row then continue processing other rows. Else...
			err = 'Your column "' + key + '" doesn\'t contain any values. Please include a value in at least one row. Or, manually define your schema instead.';
			throw err + '\n{ ' + key + ': ' + value + ' }';
		}
	},
	describeColumn: function(columns, data, i){
		_.each(data[i], function(value, key){
			if (!columns[key]){
				columns[key] = helpers.sqlizeType(value, key, data, i)
			}
		})
		return columns
	},
	describeColumns: function(data){
		var columns = {},
				i = 0;
		this.describeColumn(columns, data, i)
		// If there are null values for that object, then try the next object
		while (_.values(columns).indexOf(null) != -1){
			i++
			this.describeColumn(columns, data, i)
		}
		return columns
	},
	columnTypesToString: function(data){
		var columns = this.describeColumns(data),
				column_types = [];
		_.each(columns, function(value, key){
			column_types.push(key + ' ' + value)
		})
		return column_types.join(',')
	},
	prepValuesForInsert: function(holder, data_row, quote_char){
		var arr_holder; // In case your value is an array, run this function recursively to properly quote its values.
		if (!quote_char) {quote_char = '$$'}
		_.values(data_row).forEach(function(value){
			if (_.isString(value)){
				holder.push(quote_char + value + quote_char)
			} else if (_.isUndefined(value) || _.isNull(value) || _.isNaN(value)){
				holder.push('NULL')
			} else if (_.isNumber(value)){
				holder.push(value)
			} else if (_.isArray(value)){
				arr_holder = [];
				arr_holder = helpers.prepValuesForInsert(arr_holder, value, '"');
				holder.push(quote_char + "{" + arr_holder + "}" + quote_char);
			} else if (_.isObject(value)){
				holder.push(quote_char + JSON.stringify(value) + quote_char)
			} else if (_.isBoolean){
				holder.push(value)
			} else {
				console.log('ERROR uncaught datatype', value, 'is', typeof value)
			} // Insert date support here.
		})
		return holder.join(',');
	},
	assembleValueInsertString: function(table_name, data){
	  var stmt ='INSERT INTO ' + table_name + ' (' + _.keys(data[0]).join(',') + ') VALUES ',
	      val_arr = [];
		for (var i = 0; i < data.length; i++){
			val_arr.push('(' + helpers.prepValuesForInsert([], data[i]) + ')');
		}
		stmt += val_arr.join(',');
		return stmt;
	},
	handleErr: function(err, msg, qt){
		var pos,
				err_text = 'Error in ' + msg;
		if (err){
			pos = Number(err.position);
			if (qt) {err_text += ':\n' + qt.substr(Math.max(0, pos - err_preview_length), Math.min(pos, err_preview_length)) + '^' + qt.substr(pos, Math.min(qt.length - pos, err_preview_length)) + '\n\n'} // Display the area where the query threw an error marked by a `^`. If the error occurs within the first fifty characters, make it start at the beginning of the string.
			console.error(err_text, err)
			throw err
		}
	}
}

function connectToDb(connection_string){
	connection_string = connection_string || conString;
	client = client || new Client(connection_string);
  client.on('drain', client.end.bind(client)); //disconnect client when all queries are finished
	client.connect(function(err){
  	helpers.handleErr(err, 'database connection');
	});
	connected = true;
}

function createTableCommands(table_name, table_data, table_schema){
	var table_commands = {};
	table_commands.create = 'CREATE ' + table_type + 'TABLE ' + table_name + ' (uid BIGSERIAL PRIMARY KEY,' + ((table_schema) ? table_schema : helpers.columnTypesToString(table_data)) + ')';
	table_commands.insert = helpers.assembleValueInsertString(table_name, table_data);
	return table_commands;
}

function createAndInsert(table_commands){
	client.query(table_commands.create, function(err, result){
  	helpers.handleErr(err, 'table creation', table_commands.create)
	});
  client.query(table_commands.insert, function(err, result){
  	helpers.handleErr(err, 'row insertion', table_commands.insert)
  });
}

function createTable(table_name, table_data, table_schema){
	if (!connected) connectToDb();
	var table_commands = createTableCommands(table_name, table_data, table_schema);
	createAndInsert(table_commands);
}

function query(query_text, cb){
	var result_obj = {}
  client.query(query_text, function(err, result){
  	helpers.handleErr(err, 'query', query_text)
  	result_obj.query = query_text;
  	result_obj.rows  = result.rows
  	cb(result_obj);
  })
}
function queries(query_texts, cb){
	var results = [],
			counter = 0;

	for (var i = 0; i < query_texts.length; i++){
		(function(query_text){
			var result_obj = {};
		  client.query(query_text, function(err, result){
		  	counter++;
		  	helpers.handleErr(err, 'query', query_text)
		  	result_obj.query = query_text;
		  	result_obj.rows = result.rows;
		  	results.push(result_obj);
		  	if (counter == query_texts.length){
			  	cb(results);
		  	}
		  })
		})(query_texts[i])

	}
}
query.each = function(query_text, cb){
	var query = client.query(query_text);
  query.on('row', function(row, result){
  	cb(row, query_text);
  })
}

module.exports = {
	createTable: createTable,
	query: query,
	queries: queries,
	createTableCommands: createTableCommands,
	connect: function(connection_string){
		connectToDb(connection_string);
		return this;
	},
	errLength: function(length){
		err_preview_length = length;
		return this
	},
	temp: function(type){
		if (!type) table_type = '';
		return this
	}
}

<|endoftext|>


<commit_before>#!/usr/bin/env node
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *      Julian Viereck <julian.viereck@gmail.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

var fs = require("fs");
var copy = require('dryice').copy;

var ACE_HOME = __dirname;

function main(args) {
    var target;
    if (args.length == 3) {
        target = args[2];
        // Check if 'target' contains some allowed value.
        if (target != "normal" && target != "bm" && target != "demo") {
            target = null;
        }
    }

    if (!target) {
        console.log("--- Ace Dryice Build Tool ---");
        console.log("");
        console.log("Options:");
        console.log("  normal      Runs embedded build of Ace");
        console.log("  demo      Runs demo build of Ace");
        console.log("  bm          Runs bookmarklet build of Ace");
        process.exit(0);
    }

    var aceProject = {
        roots: [
            ACE_HOME + '/lib',
            ACE_HOME + '/demo'
        ],
        textPluginPattern: /^ace\/requirejs\/text!/
    };

    if (target == "normal") {
        ace(aceProject);
    }
    else if (target == "demo") {
        demo(aceProject);
    }
    else if (target == "bm") {
        bookmarklet(aceProject);
    }
}

function bookmarklet(aceProject) {
    var targetDir = "build/textarea";
    copy({
        source: "build_support/editor_textarea.html",
        dest:   targetDir + '/editor.html'
    });
    copy({
        source: "build_support/style.css",
        dest:   targetDir + '/style.css'
    });

    buildAce(aceProject, {
        targetDir: targetDir + "/src",
        ns: "__ace_shadowed__",
        exportModule: "ace/ext/textarea",
        compress: false,
        noconflict: true,
        suffix: ".js",
        compat: false,
        name: "ace-bookmarklet",
        workers: [],
        keybindings: []
    });
}

function ace(aceProject) {
    console.log('# ace ---------');

    // uncompressed
    buildAce(aceProject, {
        compress: false,
        noconflict: false,
        suffix: "-uncompressed.js",
        compat: true,
        name: "ace"
    });
    buildAce(aceProject, {
        compress: false,
        noconflict: true,
        suffix: "-uncompressed-noconflict.js",
        compat: true,
        name: "ace",
        workers: []
    });

    // compressed
    buildAce(aceProject, {
        compress: true,
        noconflict: false,
        suffix: ".js",
        compat: true,
        name: "ace",
        workers: []
    });
    buildAce(aceProject, {
        compress: true,
        noconflict: true,
        suffix: "-noconflict.js",
        compat: true,
        name: "ace",
        workers: []
    });

    console.log('# ace License | Readme | Changelog ---------');

    copy({
        source: "build_support/editor.html",
        dest:   "build/editor.html"
    });
    copy({
        source: ACE_HOME + "/LICENSE",
        dest:   "build/LICENSE"
    });
    copy({
        source: ACE_HOME + "/Readme.md",
        dest:   "build/Readme.md"
    });
    copy({
        source: ACE_HOME + "/ChangeLog.txt",
        dest:   "build/ChangeLog.txt"
    });
}

function demo(aceProject) {
    console.log('# kitchen sink ---------');

    var version, ref;
    try {
        version = JSON.parse(fs.readFileSync(__dirname + "/package.json")).version;
        ref = fs.readFileSync(__dirname + "/.git-ref").toString();
    } catch(e) {
        ref = "";
        version = "";
    }

    copy({
        source: "kitchen-sink.html",
        dest:   "build/kitchen-sink.html",
        filter: [ function(data) {
            return (data
                .replace("DEVEL-->", "")
                .replace("<!--DEVEL", "")
                .replace("PACKAGE-->", "")
                .replace("<!--PACKAGE", "")
                .replace("%version%", version)
                .replace("%commit%", ref)
            );
        }]
    });

    buildAce(aceProject, {
        targetDir: "build/demo/kitchen-sink",
        ns: "ace",
        requires: "kitchen-sink/demo",
        compress: false,
        noconflict: false,
        compat: false,
        name: "kitchen-sink",
        suffix: "-uncompressed.js",
        modes: [],
        keybindings: []
    });
}

function buildAce(aceProject, options) {

    var defaults = {
        targetDir: __dirname + "/build/src",
        ns: "ace",
        exportModule: "ace/ace",
        requires: null,
        compress: false,
        noconflict: false,
        suffix: ".js",
        name: "ace",
        compat: true,
        modes: [
            "css", "html", "javascript", "php", "coldfusion", "python", "lua", "xml", "ruby", "java", "c_cpp",
            "coffee", "perl", "csharp", "haxe", "svg", "clojure", "scss", "json", "groovy",
            "ocaml", "scala", "textile", "scad", "markdown", "latex", "powershell", "sql", "pgsql"
        ],
        themes: [
            "chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
            "dreamweaver", "eclipse",
            "idle_fingers", "kr_theme", "merbivore", "merbivore_soft",
            "mono_industrial", "monokai", "pastel_on_dark", "solarized_dark",
            "solarized_light", "textmate", "tomorrow", "tomorrow_night",
            "tomorrow_night_blue", "tomorrow_night_bright", "tomorrow_night_eighties",
            "twilight", "vibrant_ink"
        ],
        workers: ["javascript", "coffee", "css"],
        keybindings: ["vim", "emacs"]
    };

    for(var key in defaults)
        if (!options.hasOwnProperty(key))
            options[key] = defaults[key];

    if (!options.requires)
        options.requires = [options.exportModule];

    var filters = [copy.filter.moduleDefines, filterTextPlugin];

    if (options.noconflict) {
        filters.push(namespace(options.ns));
        if (options.exportModule)
            filters.push(exportAce(options.ns, options.exportModule, options.ns));
    } else if (options.exportModule) {
        filters.push(exportAce(options.ns, options.exportModule));
    }

    if (options.compress)
        filters.push(copy.filter.uglifyjs);

    var suffix = options.suffix;
    var targetDir = options.targetDir;
    var name = options.name;

    var project = copy.createCommonJsProject(aceProject);
    var ace = copy.createDataObject();
    copy({
        source: ["build_support/mini_require.js"],
        dest: ace
    });
    copy({
        source: [
            copy.source.commonjs({
                project: project,
                require: options.requires
            })
        ],
        filter: [ copy.filter.moduleDefines ],
        dest: ace
    });

    copy({
        source: ace,
        filter: filters,
        dest:   targetDir + '/' + name + suffix
    });

    if (options.compat) {
        project.assumeAllFilesLoaded();
        copy({
            source: [
            copy.source.commonjs({
                    project: cloneProject(project),
                    require: [ "pilot/index" ]
                })
            ],
            filter: filters,
            dest:   targetDir + "/" + name + "-compat" + suffix
        });
    }

    console.log('# ace modes ---------');

    project.assumeAllFilesLoaded();
    options.modes.forEach(function(mode) {
        console.log("mode " + mode);
        copy({
            source: [
            copy.source.commonjs({
                    project: cloneProject(project),
                    require: [ 'ace/mode/' + mode ]
                })
            ],
            filter: filters,
            dest:   targetDir + "/mode-" + mode + suffix
        });
    });

    console.log('# ace themes ---------');

    options.themes.forEach(function(theme) {
        console.log("theme " + theme);
        copy({
            source: [{
                root: ACE_HOME + '/lib',
                include: "ace/theme/" + theme + ".js"
            }],
            filter: filters,
            dest:   targetDir + "/theme-" + theme + suffix
        });
    });

    console.log('# ace worker ---------');

    options.workers.forEach(function(mode) {
        console.log("worker for " + mode + " mode");
        var worker = copy.createDataObject();
        var workerProject = copy.createCommonJsProject({
            roots: [
                ACE_HOME + '/lib'
            ],
            textPluginPattern: /^ace\/requirejs\/text!/
        });
        copy({
            source: [
                copy.source.commonjs({
                    project: workerProject,
                    require: [
                        'ace/lib/fixoldbrowsers',
                        'ace/lib/event_emitter',
                        'ace/lib/oop',
                        'ace/mode/' + mode + '_worker'
                    ]
                })
            ],
            filter: [ copy.filter.moduleDefines, filterTextPlugin ],
            dest: worker
        });
        copy({
            source: [
                ACE_HOME + "/lib/ace/worker/worker.js",
                worker
            ],
            filter: [ /* copy.filter.uglifyjs */],
            dest: targetDir + "/worker-" + mode + ".js"
        });
    });

    console.log('# ace key bindings ---------');

    // copy key bindings
    project.assumeAllFilesLoaded();
    options.keybindings.forEach(function(keybinding) {
        copy({
            source: [
            copy.source.commonjs({
                    project: cloneProject(project),
                    require: [ 'ace/keyboard/keybinding/' + keybinding ]
                })
            ],
            filter: filters,
            dest: "build/src/keybinding-" + keybinding + suffix
        });
    });
}

// TODO: replace with project.clone once it is fixed in dryice
function cloneProject(project) {
    var clone = copy.createCommonJsProject({
        roots: project.roots,
        ignores: project.ignoreRequires
    });

    Object.keys(project.currentFiles).forEach(function(module) {
        clone.currentFiles[module] = project.currentFiles[module];
    });

    Object.keys(project.ignoredFiles).forEach(function(module) {
        clone.ignoredFiles[module] = project.ignoredFiles[module];
    });

    return clone;
}

function filterTextPlugin(text) {
    return text.replace(/(['"])ace\/requirejs\/text\!/g, "$1text!");
}

function namespace(ns) {
    return function(text) {
        text = text
            .toString()
            .replace('var ACE_NAMESPACE = "";', 'var ACE_NAMESPACE = "' + ns +'";')
            .replace(/\bdefine\(/g, ns + ".define(");

        return text;
    };
}

function exportAce(ns, module, requireBase) {
    requireBase = requireBase || "window";
    module = module || "ace/ace";
    return function(text) {

        var template = function() {
            (function() {
                REQUIRE_NS.require(["MODULE"], function(a) {
                    if (!window.NS)
                        window.NS = {};
                    for (var key in a) if (a.hasOwnProperty(key))
                        NS[key] = a[key];
                });
            })();
        };

        return (text + ";" + template
            .toString()
            .replace(/MODULE/g, module)
            .replace(/REQUIRE_NS/g, requireBase)
            .replace(/NS/g, ns)
            .slice(13, -1)
        );
    };
}

if (!module.parent)
    main(process.argv);
<commit_msg>Add xquery mode.<commit_after>#!/usr/bin/env node
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *      Julian Viereck <julian.viereck@gmail.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

var fs = require("fs");
var copy = require('dryice').copy;

var ACE_HOME = __dirname;

function main(args) {
    var target;
    if (args.length == 3) {
        target = args[2];
        // Check if 'target' contains some allowed value.
        if (target != "normal" && target != "bm" && target != "demo") {
            target = null;
        }
    }

    if (!target) {
        console.log("--- Ace Dryice Build Tool ---");
        console.log("");
        console.log("Options:");
        console.log("  normal      Runs embedded build of Ace");
        console.log("  demo      Runs demo build of Ace");
        console.log("  bm          Runs bookmarklet build of Ace");
        process.exit(0);
    }

    var aceProject = {
        roots: [
            ACE_HOME + '/lib',
            ACE_HOME + '/demo'
        ],
        textPluginPattern: /^ace\/requirejs\/text!/
    };

    if (target == "normal") {
        ace(aceProject);
    }
    else if (target == "demo") {
        demo(aceProject);
    }
    else if (target == "bm") {
        bookmarklet(aceProject);
    }
}

function bookmarklet(aceProject) {
    var targetDir = "build/textarea";
    copy({
        source: "build_support/editor_textarea.html",
        dest:   targetDir + '/editor.html'
    });
    copy({
        source: "build_support/style.css",
        dest:   targetDir + '/style.css'
    });

    buildAce(aceProject, {
        targetDir: targetDir + "/src",
        ns: "__ace_shadowed__",
        exportModule: "ace/ext/textarea",
        compress: false,
        noconflict: true,
        suffix: ".js",
        compat: false,
        name: "ace-bookmarklet",
        workers: [],
        keybindings: []
    });
}

function ace(aceProject) {
    console.log('# ace ---------');

    // uncompressed
    buildAce(aceProject, {
        compress: false,
        noconflict: false,
        suffix: "-uncompressed.js",
        compat: true,
        name: "ace"
    });
    buildAce(aceProject, {
        compress: false,
        noconflict: true,
        suffix: "-uncompressed-noconflict.js",
        compat: true,
        name: "ace",
        workers: []
    });

    // compressed
    buildAce(aceProject, {
        compress: true,
        noconflict: false,
        suffix: ".js",
        compat: true,
        name: "ace",
        workers: []
    });
    buildAce(aceProject, {
        compress: true,
        noconflict: true,
        suffix: "-noconflict.js",
        compat: true,
        name: "ace",
        workers: []
    });

    console.log('# ace License | Readme | Changelog ---------');

    copy({
        source: "build_support/editor.html",
        dest:   "build/editor.html"
    });
    copy({
        source: ACE_HOME + "/LICENSE",
        dest:   "build/LICENSE"
    });
    copy({
        source: ACE_HOME + "/Readme.md",
        dest:   "build/Readme.md"
    });
    copy({
        source: ACE_HOME + "/ChangeLog.txt",
        dest:   "build/ChangeLog.txt"
    });
}

function demo(aceProject) {
    console.log('# kitchen sink ---------');

    var version, ref;
    try {
        version = JSON.parse(fs.readFileSync(__dirname + "/package.json")).version;
        ref = fs.readFileSync(__dirname + "/.git-ref").toString();
    } catch(e) {
        ref = "";
        version = "";
    }

    copy({
        source: "kitchen-sink.html",
        dest:   "build/kitchen-sink.html",
        filter: [ function(data) {
            return (data
                .replace("DEVEL-->", "")
                .replace("<!--DEVEL", "")
                .replace("PACKAGE-->", "")
                .replace("<!--PACKAGE", "")
                .replace("%version%", version)
                .replace("%commit%", ref)
            );
        }]
    });

    buildAce(aceProject, {
        targetDir: "build/demo/kitchen-sink",
        ns: "ace",
        requires: "kitchen-sink/demo",
        compress: false,
        noconflict: false,
        compat: false,
        name: "kitchen-sink",
        suffix: "-uncompressed.js",
        modes: [],
        keybindings: []
    });
}

function buildAce(aceProject, options) {

    var defaults = {
        targetDir: __dirname + "/build/src",
        ns: "ace",
        exportModule: "ace/ace",
        requires: null,
        compress: false,
        noconflict: false,
        suffix: ".js",
        name: "ace",
        compat: true,
        modes: [
            "css", "html", "javascript", "php", "coldfusion", "python", "lua", "xml", "ruby", "java", "c_cpp",
            "coffee", "perl", "csharp", "haxe", "svg", "clojure", "scss", "json", "groovy",
            "ocaml", "scala", "textile", "scad", "markdown", "latex", "powershell", "sql", "pgsql", "xquery"
        ],
        themes: [
            "chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
            "dreamweaver", "eclipse",
            "idle_fingers", "kr_theme", "merbivore", "merbivore_soft",
            "mono_industrial", "monokai", "pastel_on_dark", "solarized_dark",
            "solarized_light", "textmate", "tomorrow", "tomorrow_night",
            "tomorrow_night_blue", "tomorrow_night_bright", "tomorrow_night_eighties",
            "twilight", "vibrant_ink"
        ],
        workers: ["javascript", "coffee", "css"],
        keybindings: ["vim", "emacs"]
    };

    for(var key in defaults)
        if (!options.hasOwnProperty(key))
            options[key] = defaults[key];

    if (!options.requires)
        options.requires = [options.exportModule];

    var filters = [copy.filter.moduleDefines, filterTextPlugin];

    if (options.noconflict) {
        filters.push(namespace(options.ns));
        if (options.exportModule)
            filters.push(exportAce(options.ns, options.exportModule, options.ns));
    } else if (options.exportModule) {
        filters.push(exportAce(options.ns, options.exportModule));
    }

    if (options.compress)
        filters.push(copy.filter.uglifyjs);

    var suffix = options.suffix;
    var targetDir = options.targetDir;
    var name = options.name;

    var project = copy.createCommonJsProject(aceProject);
    var ace = copy.createDataObject();
    copy({
        source: ["build_support/mini_require.js"],
        dest: ace
    });
    copy({
        source: [
            copy.source.commonjs({
                project: project,
                require: options.requires
            })
        ],
        filter: [ copy.filter.moduleDefines ],
        dest: ace
    });

    copy({
        source: ace,
        filter: filters,
        dest:   targetDir + '/' + name + suffix
    });

    if (options.compat) {
        project.assumeAllFilesLoaded();
        copy({
            source: [
            copy.source.commonjs({
                    project: cloneProject(project),
                    require: [ "pilot/index" ]
                })
            ],
            filter: filters,
            dest:   targetDir + "/" + name + "-compat" + suffix
        });
    }

    console.log('# ace modes ---------');

    project.assumeAllFilesLoaded();
    options.modes.forEach(function(mode) {
        console.log("mode " + mode);
        copy({
            source: [
            copy.source.commonjs({
                    project: cloneProject(project),
                    require: [ 'ace/mode/' + mode ]
                })
            ],
            filter: filters,
            dest:   targetDir + "/mode-" + mode + suffix
        });
    });

    console.log('# ace themes ---------');

    options.themes.forEach(function(theme) {
        console.log("theme " + theme);
        copy({
            source: [{
                root: ACE_HOME + '/lib',
                include: "ace/theme/" + theme + ".js"
            }],
            filter: filters,
            dest:   targetDir + "/theme-" + theme + suffix
        });
    });

    console.log('# ace worker ---------');

    options.workers.forEach(function(mode) {
        console.log("worker for " + mode + " mode");
        var worker = copy.createDataObject();
        var workerProject = copy.createCommonJsProject({
            roots: [
                ACE_HOME + '/lib'
            ],
            textPluginPattern: /^ace\/requirejs\/text!/
        });
        copy({
            source: [
                copy.source.commonjs({
                    project: workerProject,
                    require: [
                        'ace/lib/fixoldbrowsers',
                        'ace/lib/event_emitter',
                        'ace/lib/oop',
                        'ace/mode/' + mode + '_worker'
                    ]
                })
            ],
            filter: [ copy.filter.moduleDefines, filterTextPlugin ],
            dest: worker
        });
        copy({
            source: [
                ACE_HOME + "/lib/ace/worker/worker.js",
                worker
            ],
            filter: [ /* copy.filter.uglifyjs */],
            dest: targetDir + "/worker-" + mode + ".js"
        });
    });

    console.log('# ace key bindings ---------');

    // copy key bindings
    project.assumeAllFilesLoaded();
    options.keybindings.forEach(function(keybinding) {
        copy({
            source: [
            copy.source.commonjs({
                    project: cloneProject(project),
                    require: [ 'ace/keyboard/keybinding/' + keybinding ]
                })
            ],
            filter: filters,
            dest: "build/src/keybinding-" + keybinding + suffix
        });
    });
}

// TODO: replace with project.clone once it is fixed in dryice
function cloneProject(project) {
    var clone = copy.createCommonJsProject({
        roots: project.roots,
        ignores: project.ignoreRequires
    });

    Object.keys(project.currentFiles).forEach(function(module) {
        clone.currentFiles[module] = project.currentFiles[module];
    });

    Object.keys(project.ignoredFiles).forEach(function(module) {
        clone.ignoredFiles[module] = project.ignoredFiles[module];
    });

    return clone;
}

function filterTextPlugin(text) {
    return text.replace(/(['"])ace\/requirejs\/text\!/g, "$1text!");
}

function namespace(ns) {
    return function(text) {
        text = text
            .toString()
            .replace('var ACE_NAMESPACE = "";', 'var ACE_NAMESPACE = "' + ns +'";')
            .replace(/\bdefine\(/g, ns + ".define(");

        return text;
    };
}

function exportAce(ns, module, requireBase) {
    requireBase = requireBase || "window";
    module = module || "ace/ace";
    return function(text) {

        var template = function() {
            (function() {
                REQUIRE_NS.require(["MODULE"], function(a) {
                    if (!window.NS)
                        window.NS = {};
                    for (var key in a) if (a.hasOwnProperty(key))
                        NS[key] = a[key];
                });
            })();
        };

        return (text + ";" + template
            .toString()
            .replace(/MODULE/g, module)
            .replace(/REQUIRE_NS/g, requireBase)
            .replace(/NS/g, ns)
            .slice(13, -1)
        );
    };
}

if (!module.parent)
    main(process.argv);
<|endoftext|>


<commit_before><commit_msg>Prevent adding null inputListener, see https://github.com/phetsims/wave-interference/issues/130<commit_after><|endoftext|>


<commit_before><commit_msg>small stuff<commit_after><|endoftext|>


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

var promisify = require('./_promisify.js')

var methods = [
  'rename',
  'ftruncate',
  'chown',
  'fchown',
  'lchown',
  'chmod',
  'fchmod',
  'stat',
  'lstat',
  'fstat',
  'link',
  'symlink',
  'readlink',
  'realpath',
  'unlink',
  'rmdir',
  'mkdir',
  'readdir',
  'close',
  'open',
  'utimes',
  'futimes',
  'fsync',
  'write',
  'read',
  'readFile',
  'writeFile',
  'appendFile',
]

methods.forEach(function (name) {
  if (typeof fs[name] === 'function')
    exports[name] = promisify(name, fs[name])
})

// don't know enough about promises to do this haha
exports.exists = promisify('exists', function exists(filename, done) {
  fs.stat(filename, function (err) {
    done(null, !err)
  })
})

// proxy the rest
Object.keys(fs).forEach(function (name) {
  if (!exports[name]) exports[name] = fs[name]
})
<commit_msg>cleanup fs<commit_after>
var fs = require('fs')

require('./_promisify_all.js')(fs, exports, [
  'rename',
  'ftruncate',
  'chown',
  'fchown',
  'lchown',
  'chmod',
  'fchmod',
  'stat',
  'lstat',
  'fstat',
  'link',
  'symlink',
  'readlink',
  'realpath',
  'unlink',
  'rmdir',
  'mkdir',
  'readdir',
  'close',
  'open',
  'utimes',
  'futimes',
  'fsync',
  'write',
  'read',
  'readFile',
  'writeFile',
  'appendFile',
])

var promisify = require('./_promisify.js')

// don't know enough about promises to do this haha
exports.exists = promisify('exists', function exists(filename, done) {
  fs.stat(filename, function (err) {
    done(null, !err)
  })
})
<|endoftext|>


<commit_before>/*jslint browser: true, on: true, eqeqeq: true, newcap: true, immed: true */

/*
	TODOs:

	Fo sho:
		- page controls
		- chrome frame / ExplorerCanvas / non canvas version?
		- show loading graphic & then fade in new page if user is ahead of the last loaded page
		- check for html5 feature support where used: diveintohtml5.org/everything.html or www.modernizr.com
		- remember position (use localStorage/cookie/sql)
		- really need to speed up enhancements, try to use webworkers

	Nice 2 have:
		- smart preload, start 5 before pointer and load from there, on navigation update preload position
		- offline access
		- thumbnail browser
		- page turn animation? (http://www.cynergysystems.com/blogs/page/rickbarraza?entry=the_secret_behind_the_page)
*/

/**
 * Merge two arrays. Any properties in b will replace the same properties in
 * a. New properties from b will be added to a.
 *
 * @param a {Object}
 * @param b {Object}
 */
function merge(a, b) {

	var prop;

	if (typeof b === "undefined") { b = {}; }

	for (prop in a) {
		if (a.hasOwnProperty(prop)) {
			if (prop in b) { continue; }
			b[prop] = a[prop];
		}
	}

	return b;
}

function ComicBook(id, srcs, opts) {

	var canvas_id = id;		// canvas element id
	this.srcs = srcs;	// array of image srcs for pages

	var defaults = {
		displayMode: "double",	// single / double
		zoomMode: "fitWidth",	// manual / fitWidth
		manga: false,			// true / false
		enhance: {}
	};

	var options = merge(defaults, opts); // options array for internal use

	var no_pages = srcs.length;
	var pages = [];		// array of preloaded Image objects
	var canvas;			// the HTML5 canvas object
	var context;		// the 2d drawing context
	var buffer = 1;		// image preload buffer level
	var loaded = [];	// the images that have been loaded so far
	var scale = 1;		// page zoom scale, 1 = 100%

	// the current page, can pass a default as a url hash
	var pointer = (parseInt(location.hash.substring(1),10) - 1) || 0;

	// enables the back button
	function checkHash() {

		var hash = parseInt(location.hash.substring(1),10) - 1;

		if (hash !== pointer && loaded.indexOf(hash) > -1) {
			pointer = hash;
			ComicBook.prototype.draw();
		}
	}

	/**
	 * Figure out the cursor position relative to the canvas.
	 *
	 * Thanks to: Mark Pilgrim & http://diveintohtml5.org/canvas.html
	 */
	function getCursorPosition(e) {

		var x; // horizontal cursor position

		// check if page relative positions exist, if not figure them out
		if (e.pageX) {
			x = e.pageX;
		} else {
			x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		}

		// make the position relative to the canvas
		x -= canvas.offsetLeft;

		// check if the user clicked on the left or right side
		return (x <= canvas.width / 2) ? 'left' : 'right';
	}

	/**
	 * Setup the canvas element for use throughout the class.
	 *
	 * @see #ComicBook.prototype.draw
	 * @see #ComicBook.prototype.enhance
	 */
	function init() {
		// setup canvas
		canvas = document.getElementById(canvas_id);
		context = canvas.getContext("2d");

		// add page controls
		// TODO: add IE event listeners too.
		canvas.addEventListener("click", ComicBook.prototype.navigation, false);
		window.addEventListener("hashchange", checkHash, false);
		//setInterval(function() { checkHash(); }, 300); // TODO: enable this when there is no onhashchange event
	}

	/*
	 * @see #preload
	 */
	ComicBook.prototype.draw = function () {

		init();

		// preload images if needed
		if (pages.length !== no_pages) { this.preload(); }
		else { this.drawPage(); }
	};

	/*
	 * Zoom the canvas
	 *
	 * @param new_scale {Number} Scale the canvas to this ratio
	 */
	ComicBook.prototype.zoom = function (new_scale) {
		options.zoomMode = "manual";
		scale = new_scale;
		if (typeof pages[pointer] === "object") { this.drawPage(); }
	};

	/**
	 * Preload all images, draw the page only after a given number have been loaded.
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.preload = function () {

		var srcs = this.srcs;

		if (no_pages < buffer) { buffer = no_pages; } // don't get stuck if the buffer level is higher than the number of pages

		var i = pointer; // the current page counter for this method
		//if (i - buffer >= 0) { i = i - buffer; } // start loading from the first requested page - buffer

		// show load status panel
		if ($("#status").length === 0) {
			$(canvas).after('

');
		}

		// I am using recursion instead of a forEach loop so that the next image is
		// only loaded when the previous one has completely finished
		function preload(i) {

			var page = new Image();

			$("#status p").text("loading page " + (i + 1) + " of " + no_pages);

			page.src = srcs[i];

			page.onload = function () {

				pages[i] = this;
				loaded.push(i);

				// start to load from the begining if loading started midway
				if (i === no_pages-1 && loaded.length !== no_pages) {
					i = -1;
				}

				// there are still more pages to load, do it
				if (loaded.length < no_pages) {
					i++;
					preload(i);
				}

				// start rendering the comic when the buffer level has been reached (FIXME: buggy, fails if trying to load the last couple of pages)
				if (loaded.length === pointer + buffer) { ComicBook.prototype.drawPage(); }
				if (loaded.length === no_pages) { $("#status").fadeOut(150).remove(); }
			};
		}

		// manually trigger the first load
		preload(i);
	};

	/**
	 * Draw the current page in the canvas
	 *
	 * TODO: break this down into drawSinglePage() & drawDoublePage()?
	 * TODO: if the current browser doesn't have canvas support, use img tags
	 */
	ComicBook.prototype.drawPage = function() {

		var zoom_scale;
		var offsetW = 0, offsetH = 0;
		var page = pages[pointer];
		var page2 = pages[pointer + 1];

		if (typeof page !== "object") { throw "invalid page type '"+ typeof page +"'"; }

		var width = page.width;

		// reset the canvas to stop duplicate pages showing
		canvas.width = 0;
		canvas.height = 0;

		if (options.displayMode === "double") {

			// for double page spreads, factor in the width of both pages
			if (typeof page2 === "object") { width += page2.width; }

			// if this is the last page and there is no page2, still keep the canvas wide
			else { width += width; }
		}

		// update the page scale if a non manual mode has been chosen
		switch(options.zoomMode) {

			case "manual":
				document.body.style.overflowX = "auto";
				zoom_scale = (options.displayMode === "double") ? scale * 2 : scale;
				break;

			case "fitWidth":
				document.body.style.overflowX = "hidden";
				zoom_scale =  (window.innerWidth > width) ? ((window.innerWidth - width) / window.innerWidth) + 1 // scale up if the window is wider than the page
					  : window.innerWidth / width; // scale down if the window is narrower than the page
				break;

			default:throw "invalid zoomMode";
		}

		var canvas_width  = page.width * zoom_scale;
		var canvas_height = page.height * zoom_scale;

		var page_width = (options.zoomMode === "manual") ? page.width * scale : canvas_width;
		var page_height = (options.zoomMode === "manual") ? page.height * scale : canvas_height;

		canvas_height = page_height;

		// make sure the canvas is always at least full screen, even if the page is more narrow than the screen
		canvas.width = (canvas_width < window.innerWidth) ? window.innerWidth : canvas_width;
		canvas.height = (canvas_height < window.innerHeight) ? window.innerHeight : canvas_height;

		// disable scrollbars if not needed
		document.body.style.overflowX = (canvas_width < window.innerWidth) ? "hidden" : "auto";
		document.body.style.overflowY = (canvas_height < window.innerHeight) ? "hidden" : "auto";

		// work out a horizontal position that will keep the pages always centred
		if (canvas_width < window.innerWidth && options.zoomMode === "manual") {
			offsetW = (window.innerWidth - page_width) / 2;
			if (options.displayMode === "double") { offsetW = offsetW - page_width / 2; }
		}

		// work out a vertical position that will keep the pages always centred
		if (canvas_height < window.innerHeight && options.zoomMode === "manual") {
			offsetH = (window.innerHeight - page_height) / 2;
		}

		// in manga double page mode reverse the page(s)
		if (options.manga && options.displayMode === "double") {
			var tmpPage = page;
			var tmpPage2 = page2; // FIXME: check this exists before using
			page = tmpPage2;
			page2 = tmpPage;
		}

		// draw the page(s)
		context.drawImage(page, offsetW, offsetH, page_width, page_height);
		if (options.displayMode === "double" && typeof page2 === "object") { context.drawImage(page2, page_width + offsetW, offsetH, page_width, page_height); }

		location.hash = pointer + 1;

		// apply any image enhancements previously defined
		$.each(options.enhance, function(action, options) {
			ComicBook.prototype.enhance[action](options);
		});
	};

	/**
	 * Increment the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawNextPage = function () {
		if (pointer + 1 < pages.length) {
			pointer += (options.displayMode === "single") ? 1 : 2;
			this.drawPage();
		}
	};

	/**
	 * Decrement the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawPrevPage = function () {
		if (pointer > 0) {
			pointer -= (options.displayMode === "single") ? 1 : 2;
			this.drawPage();
		}
	};

	/**
	 * Apply image enhancements to the canvas.
	 *
	 * Powered by the awesome Pixastic: http://www.pixastic.com/
	 *
	 * TODO: reset & apply all image enhancements each time before applying new one
	 *
	 * TODO: abstract this into an "Enhance" object, separate from ComicBook?
	 */
	ComicBook.prototype.enhance = {

		/**
		 * Reset enhancements.
		 * This can reset a specific enhancement if the method name is passed, or
		 * it will reset all.
		 *
		 * @param method {string} the specific enhancement to reset
		 */
		reset: function (method) {
			if (!method) {
				options.enhance = {};
			} else {
				delete options.enhance[method];
			}
			ComicBook.prototype.drawPage();
		},

		/**
		 * Adjust brightness / contrast
		 *
		 * params
		 *    brightness (int) -150 to 150
		 *    contrast: (float) -1 to infinity
		 *
		 * @param {Object} params Brightness & contrast levels
		 * @param {Boolean} reset Reset before applying more enhancements?
		 */
		brightness: function (params, reset) {

			if (reset !== false) { this.reset("brightness"); }

			// merge user options with defaults
			var opts = merge({ brightness: 0, contrast: 0 }, params);

			// remember options for later
			options.enhance.brightness = opts;

			// run the enhancement
			Pixastic.process(canvas, "brightness", {
				brightness: opts.brightness,
				contrast: opts.contrast,
				legacy: true
			});

			init();
		},

		/**
		 * Force black and white
		 */
		desaturate: function () {

			options.enhance.desaturate = {};

			Pixastic.process(canvas, "desaturate", { average : false });

			init();
		},

		/**
		 * Sharpen
		 *
		 * options:
		 *   amount: number (-1 to infinity)
		 *
		 * @param {Object} options
		 */
		sharpen: function (params) {

			var opts = merge({ amount: 0 }, params);

			options.enhance.sharpen = opts;

			Pixastic.process(canvas, "sharpen", {
				amount: opts.amount
			});

			init();
		}
	};

	ComicBook.prototype.navigation = function (e) {

		if (e.type === "click") {

			var side = getCursorPosition(e);

			window.scroll(0,0); // make sure the top of the page is in view

			// western style (left to right)
			if (!options.manga) {
				if (side === "left") { ComicBook.prototype.drawPrevPage(); }
				if (side === "right") { ComicBook.prototype.drawNextPage(); }
			}
			// manga style (right to left)
			else {
				if (side === "left") { ComicBook.prototype.drawNextPage(); }
				if (side === "right") { ComicBook.prototype.drawPrevPage(); }
			}
		}
	};
}
<commit_msg>fixed minor preload & hash nav bugs<commit_after>/*jslint browser: true, on: true, eqeqeq: true, newcap: true, immed: true */

/*
	TODOs:

	Fo sho:
		- page controls
		- chrome frame / ExplorerCanvas / non canvas version?
		- show loading graphic & then fade in new page if user is ahead of the last loaded page
		- check for html5 feature support where used: diveintohtml5.org/everything.html or www.modernizr.com
		- remember position (use localStorage/cookie/sql)
		- really need to speed up enhancements, try to use webworkers

	Nice 2 have:
		- smart preload, start 5 before pointer and load from there, on navigation update preload position
		- offline access
		- thumbnail browser
		- page turn animation? (http://www.cynergysystems.com/blogs/page/rickbarraza?entry=the_secret_behind_the_page)
*/

/**
 * Merge two arrays. Any properties in b will replace the same properties in
 * a. New properties from b will be added to a.
 *
 * @param a {Object}
 * @param b {Object}
 */
function merge(a, b) {

	var prop;

	if (typeof b === "undefined") { b = {}; }

	for (prop in a) {
		if (a.hasOwnProperty(prop)) {
			if (prop in b) { continue; }
			b[prop] = a[prop];
		}
	}

	return b;
}

function ComicBook(id, srcs, opts) {

	var canvas_id = id;		// canvas element id
	this.srcs = srcs;	// array of image srcs for pages

	var defaults = {
		displayMode: "double",	// single / double
		zoomMode: "fitWidth",	// manual / fitWidth
		manga: false,			// true / false
		enhance: {}
	};

	var options = merge(defaults, opts); // options array for internal use

	var no_pages = srcs.length;
	var pages = [];		// array of preloaded Image objects
	var canvas;			// the HTML5 canvas object
	var context;		// the 2d drawing context
	var buffer = 1;		// image preload buffer level
	var loaded = [];	// the images that have been loaded so far
	var scale = 1;		// page zoom scale, 1 = 100%

	// the current page, can pass a default as a url hash
	var pointer = (parseInt(location.hash.substring(1),10) - 1) || 0;

	// enables the back button
	function checkHash() {

		var hash = parseInt(location.hash.substring(1),10) - 1 || 0;

		if (hash !== pointer && loaded.indexOf(hash) > -1) {
			pointer = hash;
			ComicBook.prototype.draw();
		}
	}

	/**
	 * Figure out the cursor position relative to the canvas.
	 *
	 * Thanks to: Mark Pilgrim & http://diveintohtml5.org/canvas.html
	 */
	function getCursorPosition(e) {

		var x; // horizontal cursor position

		// check if page relative positions exist, if not figure them out
		if (e.pageX) {
			x = e.pageX;
		} else {
			x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		}

		// make the position relative to the canvas
		x -= canvas.offsetLeft;

		// check if the user clicked on the left or right side
		return (x <= canvas.width / 2) ? 'left' : 'right';
	}

	/**
	 * Setup the canvas element for use throughout the class.
	 *
	 * @see #ComicBook.prototype.draw
	 * @see #ComicBook.prototype.enhance
	 */
	function init() {
		// setup canvas
		canvas = document.getElementById(canvas_id);
		context = canvas.getContext("2d");

		// add page controls
		// TODO: add IE event listeners too.
		canvas.addEventListener("click", ComicBook.prototype.navigation, false);
		window.addEventListener("hashchange", checkHash, false);
		//setInterval(function() { checkHash(); }, 300); // TODO: enable this when there is no onhashchange event
	}

	/*
	 * @see #preload
	 */
	ComicBook.prototype.draw = function () {

		init();

		// preload images if needed
		if (pages.length !== no_pages) { this.preload(); }
		else { this.drawPage(); }
	};

	/*
	 * Zoom the canvas
	 *
	 * @param new_scale {Number} Scale the canvas to this ratio
	 */
	ComicBook.prototype.zoom = function (new_scale) {
		options.zoomMode = "manual";
		scale = new_scale;
		if (typeof pages[pointer] === "object") { this.drawPage(); }
	};

	/**
	 * Preload all images, draw the page only after a given number have been loaded.
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.preload = function () {

		//var srcs = this.srcs;

		if (no_pages < buffer) { buffer = no_pages; } // don't get stuck if the buffer level is higher than the number of pages

		var i = pointer; // the current page counter for this method
		//if (i - buffer >= 0) { i = i - buffer; } // start loading from the first requested page - buffer

		// show load status panel
		if ($("#status").length === 0) {
			$(canvas).after('

');
		}

		// I am using recursion instead of a forEach loop so that the next image is
		// only loaded when the previous one has completely finished
		function preload(i) {

			var page = new Image();

			$("#status p").text("loading page " + (i + 1) + " of " + no_pages);

			page.src = srcs[i];

			page.onload = function () {

				pages[i] = this;
				loaded.push(i);

				// start to load from the begining if loading started midway
				if (i === no_pages-1 && loaded.length !== no_pages) {
					i = -1;
				}

				// there are still more pages to load, do it
				if (loaded.length < no_pages) {
					i++;
					preload(i);
				}

				//console.log(loaded[loaded.length-1], pointer, pointer + buffer);

				// start rendering the comic when the buffer level has been reached (FIXME: buggy, fails if trying to load the last couple of pages)
				if (loaded[loaded.length-1] === pointer + buffer) { ComicBook.prototype.drawPage(); }
				if (loaded.length === no_pages) { $("#status").fadeOut(150).remove(); }
			};
		}

		// manually trigger the first load
		preload(i);
	};

	/**
	 * Draw the current page in the canvas
	 *
	 * TODO: break this down into drawSinglePage() & drawDoublePage()?
	 * TODO: if the current browser doesn't have canvas support, use img tags
	 */
	ComicBook.prototype.drawPage = function() {

		var zoom_scale;
		var offsetW = 0, offsetH = 0;
		var page = pages[pointer];
		var page2 = pages[pointer + 1];

		if (typeof page !== "object") { throw "invalid page type '"+ typeof page +"'"; }

		var width = page.width;

		// reset the canvas to stop duplicate pages showing
		canvas.width = 0;
		canvas.height = 0;

		if (options.displayMode === "double") {

			// for double page spreads, factor in the width of both pages
			if (typeof page2 === "object") { width += page2.width; }

			// if this is the last page and there is no page2, still keep the canvas wide
			else { width += width; }
		}

		// update the page scale if a non manual mode has been chosen
		switch(options.zoomMode) {

			case "manual":
				document.body.style.overflowX = "auto";
				zoom_scale = (options.displayMode === "double") ? scale * 2 : scale;
				break;

			case "fitWidth":
				document.body.style.overflowX = "hidden";
				zoom_scale =  (window.innerWidth > width) ? ((window.innerWidth - width) / window.innerWidth) + 1 // scale up if the window is wider than the page
					  : window.innerWidth / width; // scale down if the window is narrower than the page
				break;

			default:throw "invalid zoomMode";
		}

		var canvas_width  = page.width * zoom_scale;
		var canvas_height = page.height * zoom_scale;

		var page_width = (options.zoomMode === "manual") ? page.width * scale : canvas_width;
		var page_height = (options.zoomMode === "manual") ? page.height * scale : canvas_height;

		canvas_height = page_height;

		// make sure the canvas is always at least full screen, even if the page is more narrow than the screen
		canvas.width = (canvas_width < window.innerWidth) ? window.innerWidth : canvas_width;
		canvas.height = (canvas_height < window.innerHeight) ? window.innerHeight : canvas_height;

		// disable scrollbars if not needed
		document.body.style.overflowX = (canvas_width < window.innerWidth) ? "hidden" : "auto";
		document.body.style.overflowY = (canvas_height < window.innerHeight) ? "hidden" : "auto";

		// work out a horizontal position that will keep the pages always centred
		if (canvas_width < window.innerWidth && options.zoomMode === "manual") {
			offsetW = (window.innerWidth - page_width) / 2;
			if (options.displayMode === "double") { offsetW = offsetW - page_width / 2; }
		}

		// work out a vertical position that will keep the pages always centred
		if (canvas_height < window.innerHeight && options.zoomMode === "manual") {
			offsetH = (window.innerHeight - page_height) / 2;
		}

		// in manga double page mode reverse the page(s)
		if (options.manga && options.displayMode === "double") {
			var tmpPage = page;
			var tmpPage2 = page2; // FIXME: check this exists before using
			page = tmpPage2;
			page2 = tmpPage;
		}

		// draw the page(s)
		context.drawImage(page, offsetW, offsetH, page_width, page_height);
		if (options.displayMode === "double" && typeof page2 === "object") { context.drawImage(page2, page_width + offsetW, offsetH, page_width, page_height); }

		location.hash = pointer + 1;

		// apply any image enhancements previously defined
		$.each(options.enhance, function(action, options) {
			ComicBook.prototype.enhance[action](options);
		});
	};

	/**
	 * Increment the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawNextPage = function () {
		if (pointer + 1 < pages.length) {
			pointer += (options.displayMode === "single") ? 1 : 2;
			this.drawPage();
		}
	};

	/**
	 * Decrement the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawPrevPage = function () {
		if (pointer > 0) {
			pointer -= (options.displayMode === "single") ? 1 : 2;
			this.drawPage();
		}
	};

	/**
	 * Apply image enhancements to the canvas.
	 *
	 * Powered by the awesome Pixastic: http://www.pixastic.com/
	 *
	 * TODO: reset & apply all image enhancements each time before applying new one
	 *
	 * TODO: abstract this into an "Enhance" object, separate from ComicBook?
	 */
	ComicBook.prototype.enhance = {

		/**
		 * Reset enhancements.
		 * This can reset a specific enhancement if the method name is passed, or
		 * it will reset all.
		 *
		 * @param method {string} the specific enhancement to reset
		 */
		reset: function (method) {
			if (!method) {
				options.enhance = {};
			} else {
				delete options.enhance[method];
			}
			ComicBook.prototype.drawPage();
		},

		/**
		 * Adjust brightness / contrast
		 *
		 * params
		 *    brightness (int) -150 to 150
		 *    contrast: (float) -1 to infinity
		 *
		 * @param {Object} params Brightness & contrast levels
		 * @param {Boolean} reset Reset before applying more enhancements?
		 */
		brightness: function (params, reset) {

			if (reset !== false) { this.reset("brightness"); }

			// merge user options with defaults
			var opts = merge({ brightness: 0, contrast: 0 }, params);

			// remember options for later
			options.enhance.brightness = opts;

			// run the enhancement
			Pixastic.process(canvas, "brightness", {
				brightness: opts.brightness,
				contrast: opts.contrast,
				legacy: true
			});

			init();
		},

		/**
		 * Force black and white
		 */
		desaturate: function () {

			options.enhance.desaturate = {};

			Pixastic.process(canvas, "desaturate", { average : false });

			init();
		},

		/**
		 * Sharpen
		 *
		 * options:
		 *   amount: number (-1 to infinity)
		 *
		 * @param {Object} options
		 */
		sharpen: function (params) {

			var opts = merge({ amount: 0 }, params);

			options.enhance.sharpen = opts;

			Pixastic.process(canvas, "sharpen", {
				amount: opts.amount
			});

			init();
		}
	};

	ComicBook.prototype.navigation = function (e) {

		if (e.type === "click") {

			var side = getCursorPosition(e);

			window.scroll(0,0); // make sure the top of the page is in view

			// western style (left to right)
			if (!options.manga) {
				if (side === "left") { ComicBook.prototype.drawPrevPage(); }
				if (side === "right") { ComicBook.prototype.drawNextPage(); }
			}
			// manga style (right to left)
			else {
				if (side === "left") { ComicBook.prototype.drawNextPage(); }
				if (side === "right") { ComicBook.prototype.drawPrevPage(); }
			}
		}
	};
}
<|endoftext|>


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

var Emitter = require('events').EventEmitter
  , path = require('path')
  , dirname = path.dirname
  , basename = path.basename
  , extname = path.extname
  , join = path.join
  , mkdir = require('mkdirp').mkdirp
  , request = require('superagent')
  , debug = require('debug')('component:installer')
  , Batch = require('batch')
  , fs = require('fs');

/**
 * Expose installer.
 */

module.exports = Installer;

/**
 * Initialize a new `Installer` with
 * the given `pkg` name and `dest` dir.
 *
 * @param {String} pkg
 * @param {String} dest
 * @api private
 */

function Installer(pkg, dest) {
  debug('installing %s to %s', pkg, dest);
  if (!pkg) throw new Error('pkg required');
  if (!dest) throw new Error('destination required');
  this.name = pkg;
  this.dest = dest;
  this.version = 'master';
}

/**
 * Inherit from `Emitter.prototype`.
 */

Installer.prototype.__proto__ = Emitter.prototype;

/**
 * Return dirname for this package.
 * For example "component/dialog"
 * becomes "component-dialog".
 *
 * @return {String}
 * @api private
 */

Installer.prototype.dirname = function(){
  return join(this.dest, this.name.split('/').join('-'));
};

/**
 * Join `path` to this package's dirname.
 *
 * @param {String} path
 * @return {String}
 * @api private
 */

Installer.prototype.join = function(path){
  return join(this.dirname(), path);
};

/**
 * Return URL to `file`.
 *
 * @param {String} file
 * @return {String}
 * @api private
 */

Installer.prototype.url = function(file){
  return 'https://raw.github.com/' + this.name + '/' + this.version + '/' + file;
};

/**
 * Get component.json and callback `fn(err, obj)`.
 *
 * @param {Function} fn
 * @api private
 */

Installer.prototype.getJSON = function(fn){
  var self = this;
  var url = this.url('component.json');
  request.get(url, function(res){
    if (res.ok) {
      fn(null, JSON.parse(res.text));
    } else {
      fn(new Error('failed to fetch ' + url));
    }
  });
};

/**
 * Fetch `files` and write them to disk and callback `fn(err)`.
 *
 * @param {Array} files
 * @param {Function} fn
 * @api private
 */

Installer.prototype.getFiles = function(files, fn){
  var self = this;
  var batch = new Batch;

  files.forEach(function(file){
    batch.push(function(done){
      var url = self.url(file);
      self.emit('file:start', file, url);
      request.get(url, function(res){
        if (res.ok) {
          self.writeFile(file, res.text, done);
        } else {
          done(new Error('failed to fetch ' + url));
        }
      });
    });
  });

  mkdir(this.dirname(), function(err){
    if (err) return fn(err);
    batch.end(fn);
  });
};

/**
 * Write `file` with `str` contents to disk and callback `fn(err)`.
 *
 * @param {String} file
 * @param {String} str
 * @param {Function} fn
 * @api private
 */

Installer.prototype.writeFile = function(file, str, fn){
  fs.writeFile(this.join(file), str, fn);
};

/**
 * Install the component.
 *
 * @api public
 */

Installer.prototype.install = function(){
  var self = this;
  this.getJSON(function(err, json){
    if (err) return self.emit('error', err);
    var files = [];
    if (json.scripts) files = files.concat(json.scripts);
    if (json.styles) files = files.concat(json.styles);
    if (json.templates) files = files.concat(json.templates);
    self.getFiles(files, function(){
      self.emit('end');
    });
  });
};
<commit_msg>add saving of component.json<commit_after>
/**
 * Module dependencies.
 */

var Emitter = require('events').EventEmitter
  , path = require('path')
  , dirname = path.dirname
  , basename = path.basename
  , extname = path.extname
  , join = path.join
  , mkdir = require('mkdirp').mkdirp
  , request = require('superagent')
  , debug = require('debug')('component:installer')
  , Batch = require('batch')
  , fs = require('fs');

/**
 * Expose installer.
 */

module.exports = Installer;

/**
 * Initialize a new `Installer` with
 * the given `pkg` name and `dest` dir.
 *
 * @param {String} pkg
 * @param {String} dest
 * @api private
 */

function Installer(pkg, dest) {
  debug('installing %s to %s', pkg, dest);
  if (!pkg) throw new Error('pkg required');
  if (!dest) throw new Error('destination required');
  this.name = pkg;
  this.dest = dest;
  this.version = 'master';
}

/**
 * Inherit from `Emitter.prototype`.
 */

Installer.prototype.__proto__ = Emitter.prototype;

/**
 * Return dirname for this package.
 * For example "component/dialog"
 * becomes "component-dialog".
 *
 * @return {String}
 * @api private
 */

Installer.prototype.dirname = function(){
  return join(this.dest, this.name.split('/').join('-'));
};

/**
 * Join `path` to this package's dirname.
 *
 * @param {String} path
 * @return {String}
 * @api private
 */

Installer.prototype.join = function(path){
  return join(this.dirname(), path);
};

/**
 * Return URL to `file`.
 *
 * @param {String} file
 * @return {String}
 * @api private
 */

Installer.prototype.url = function(file){
  return 'https://raw.github.com/' + this.name + '/' + this.version + '/' + file;
};

/**
 * Get component.json and callback `fn(err, obj)`.
 *
 * @param {Function} fn
 * @api private
 */

Installer.prototype.getJSON = function(fn){
  var self = this;
  var url = this.url('component.json');
  request.get(url, function(res){
    if (res.ok) {
      fn(null, JSON.parse(res.text));
    } else {
      fn(new Error('failed to fetch ' + url));
    }
  });
};

/**
 * Fetch `files` and write them to disk and callback `fn(err)`.
 *
 * @param {Array} files
 * @param {Function} fn
 * @api private
 */

Installer.prototype.getFiles = function(files, fn){
  var self = this;
  var batch = new Batch;

  files.forEach(function(file){
    batch.push(function(done){
      var url = self.url(file);
      self.emit('file:start', file, url);
      request.get(url, function(res){
        if (res.ok) {
          self.writeFile(file, res.text, done);
        } else {
          done(new Error('failed to fetch ' + url));
        }
      });
    });
  });

  mkdir(this.dirname(), function(err){
    if (err) return fn(err);
    batch.end(fn);
  });
};

/**
 * Write `file` with `str` contents to disk and callback `fn(err)`.
 *
 * @param {String} file
 * @param {String} str
 * @param {Function} fn
 * @api private
 */

Installer.prototype.writeFile = function(file, str, fn){
  fs.writeFile(this.join(file), str, fn);
};

/**
 * Install the component.
 *
 * @api public
 */

Installer.prototype.install = function(){
  var self = this;
  var batch = new Batch;
  this.getJSON(function(err, json){
    if (err) return self.emit('error', err);
    var files = [];
    if (json.scripts) files = files.concat(json.scripts);
    if (json.styles) files = files.concat(json.styles);
    if (json.templates) files = files.concat(json.templates);

    batch.push(function(done){
      json = JSON.stringify(json, null, 2);
      self.writeFile('component.json', json, done);
    });

    batch.push(function(done){
      self.getFiles(files, done);
    });

    batch.end(function(err){
      if (err) return self.emit('error', err);
      self.emit('end');
    });
  });
};
<|endoftext|>


<commit_before>/**
 * The 'id' function is essentially the "base class" for all Objective-C
 * objects that get passed around JS-land.
 */

var proto = exports.proto = Object.create(Function.prototype)
  , core  = require('./core')
  , types = require('./types')
  , SEL   = require('./sel')

/**
 * Wraps up a pointer that is expected to be a compatible Objective-C
 * object that can recieve messages.
 */
exports.wrap = function wrap (pointer) {

  // This 'id' function is syntax sugar around the msgSend function attached to
  // it. 'msgSend' is expecting the selector first, an Array of args second, so
  // this function just massages it into place and returns the result.
  function id () {
    var args = []
      , sel
    if (arguments.length === 1) {
      var arg = arguments[0]
      if (arg.constructor.name == 'String') {
        sel = arg
      } else {
        sel = []
        Object.keys(arg).forEach(function (s) {
          sel.push(s)
          args.push(arg[s])
        })
        sel.push('')
        sel = sel.join(':')
      }
    } else {
      sel = []
      var len = arguments.length
      for (var i=0; i<len; i+=2) {
        sel.push(arguments[i])
        args.push(arguments[i+1])
      }
      sel.push('')
      sel = sel.join(':')
    }
    return id.msgSend(sel, args)
  }

  // Save a reference to the pointer for use by the prototype functions
  id.pointer = pointer;
  // Morph into a MUTANT FUNCTION FREAK!!1!
  id.__proto__ = proto;
  return id;
}
// Avoid a circular dep.
core._idwrap = exports.wrap;

proto.msgSend = function msgSend (sel, args) {
  var types = this._getTypes(sel)
    , argTypes = types[1]
    , msgSendFunc = core.get_objc_msgSend(types)
    , selRef = SEL.toSEL(sel)
    , unwrappedArgs = args.map(function (a, i) {
        return core.unwrapValue(a, argTypes[i+2]);
      })
    , rtn = msgSendFunc.apply(null, [ this.pointer, selRef ].concat(unwrappedArgs))
  //console.error(types);
  //console.error(rtn);
  // Process the return value into a wrapped value if needed
  return core.wrapValue(rtn, types[0]);
}

/**
 * Accepts a SEL and queries the current object for the return type and
 * argument types for the given selector. If current object does not implment
 * that selector, then check the superclass, and repeat recursively until
 * a subclass that responds to the selector is found, or until the base class
 * is found (in which case the current obj does not respond to 'sel' and we
 * should throw an Error).
 */
proto._getTypes = function getTypes (sel) {
  var c = this.getClass()
    , t = c._getTypesClass(sel, this.isClass)
  if (!t) throw new Error('Object does not respond to selector: '+sel);
  return t;
}

/**
 * Retrieves the wrapped Class instance for this object.
 */
proto.getClass = function getClass () {
  return exports._wrapClass(this._getClassPointer());
}

/**
 * Returns the node-ffi pointer for the class of this object.
 */
proto._getClassPointer = function getClassPointer () {
  return core.object_getClass(this.pointer)
}

/**
 * Calls 'object_getClassName()' on this object.
 */
proto.getClassName = function () {
  return core.object_getClassName(this.pointer);
}

/**
 * Returns an Array of Strings of the names of methods that the current object
 * will respond to. This function can iterate through the object's superclasses
 * recursively, if you specify a 'maxDepth' number argument.
 */
proto.methods = function methods (maxDepth) {
  var numMethods = new core.Pointer(core.TYPE_SIZE_MAP.uint32)
    , rtn = []
    , classPointer = this._getClassPointer()
    , md = maxDepth || 1
    , depth = 0
  while (depth++ < md && !classPointer.isNull()) {
    var methods = core.class_copyMethodList(classPointer, numMethods)
      , p = methods
      , count = numMethods.getUInt32()
    for (var i=0; i<count; i++) {
      var cur = p.getPointer()
        , name = SEL.toString(core.method_getName(cur))
      if (!~rtn.indexOf(name)) {
        rtn.push(name)
      }
      p = p.seek(core.TYPE_SIZE_MAP.pointer)
    }
    core.free(methods)
    classPointer = core.class_getSuperclass(classPointer)
  }
  return rtn
}

/**
 * The id wrap's overidden toString() function proxies up to the id's
 * description method:  [[id description] UTF8String]
 */
proto.toString = function toString () {
  return this('description')('UTF8String');
}
<commit_msg>Use the core.js unwrapValues() function in id#msgSend().<commit_after>/**
 * The 'id' function is essentially the "base class" for all Objective-C
 * objects that get passed around JS-land.
 */

var proto = exports.proto = Object.create(Function.prototype)
  , core  = require('./core')
  , types = require('./types')
  , SEL   = require('./sel')

/**
 * Wraps up a pointer that is expected to be a compatible Objective-C
 * object that can recieve messages.
 */
exports.wrap = function wrap (pointer) {

  // This 'id' function is syntax sugar around the msgSend function attached to
  // it. 'msgSend' is expecting the selector first, an Array of args second, so
  // this function just massages it into place and returns the result.
  function id () {
    var args = []
      , sel
    if (arguments.length === 1) {
      var arg = arguments[0]
      if (arg.constructor.name == 'String') {
        sel = arg
      } else {
        sel = []
        Object.keys(arg).forEach(function (s) {
          sel.push(s)
          args.push(arg[s])
        })
        sel.push('')
        sel = sel.join(':')
      }
    } else {
      sel = []
      var len = arguments.length
      for (var i=0; i<len; i+=2) {
        sel.push(arguments[i])
        args.push(arguments[i+1])
      }
      sel.push('')
      sel = sel.join(':')
    }
    return id.msgSend(sel, args)
  }

  // Save a reference to the pointer for use by the prototype functions
  id.pointer = pointer;
  // Morph into a MUTANT FUNCTION FREAK!!1!
  id.__proto__ = proto;
  return id;
}
// Avoid a circular dep.
core._idwrap = exports.wrap;

proto.msgSend = function msgSend (sel, args) {
  var types = this._getTypes(sel)
    , argTypes = types[1]
    , msgSendFunc = core.get_objc_msgSend(types)
    , unwrappedArgs = core.unwrapValues([this, sel].concat(args), argTypes)
    , rtn = msgSendFunc.apply(null, unwrappedArgs)
  // Process the return value into a wrapped value if needed
  return core.wrapValue(rtn, types[0]);
}

/**
 * Accepts a SEL and queries the current object for the return type and
 * argument types for the given selector. If current object does not implment
 * that selector, then check the superclass, and repeat recursively until
 * a subclass that responds to the selector is found, or until the base class
 * is found (in which case the current obj does not respond to 'sel' and we
 * should throw an Error).
 */
proto._getTypes = function getTypes (sel) {
  var c = this.getClass()
    , t = c._getTypesClass(sel, this.isClass)
  if (!t) throw new Error('Object does not respond to selector: '+sel);
  return t;
}

/**
 * Retrieves the wrapped Class instance for this object.
 */
proto.getClass = function getClass () {
  return exports._wrapClass(this._getClassPointer());
}

/**
 * Returns the node-ffi pointer for the class of this object.
 */
proto._getClassPointer = function getClassPointer () {
  return core.object_getClass(this.pointer)
}

/**
 * Calls 'object_getClassName()' on this object.
 */
proto.getClassName = function () {
  return core.object_getClassName(this.pointer);
}

/**
 * Returns an Array of Strings of the names of methods that the current object
 * will respond to. This function can iterate through the object's superclasses
 * recursively, if you specify a 'maxDepth' number argument.
 */
proto.methods = function methods (maxDepth) {
  var numMethods = new core.Pointer(core.TYPE_SIZE_MAP.uint32)
    , rtn = []
    , classPointer = this._getClassPointer()
    , md = maxDepth || 1
    , depth = 0
  while (depth++ < md && !classPointer.isNull()) {
    var methods = core.class_copyMethodList(classPointer, numMethods)
      , p = methods
      , count = numMethods.getUInt32()
    for (var i=0; i<count; i++) {
      var cur = p.getPointer()
        , name = SEL.toString(core.method_getName(cur))
      if (!~rtn.indexOf(name)) {
        rtn.push(name)
      }
      p = p.seek(core.TYPE_SIZE_MAP.pointer)
    }
    core.free(methods)
    classPointer = core.class_getSuperclass(classPointer)
  }
  return rtn
}

/**
 * The id wrap's overidden toString() function proxies up to the id's
 * description method:  [[id description] UTF8String]
 */
proto.toString = function toString () {
  return this('description')('UTF8String');
}
<|endoftext|>


<commit_before>const iocane = require("iocane");
const webdavFS = require("webdav-fs");

module.exports = {
    Archive: require("./system/Archive.js"),
    ArchiveManager: require("./system/ArchiveManager.js"),
    Westley: require("./system/Westley.js"),
    Inigo: require("./system/InigoGenerator.js"),
    Workspace: require("./system/Workspace.js"),

    createCredentials: require("./system/credentials.js"),
    Model: require("./system/Model.js"),

    Group: require("./system/Group.js"),
    Entry: require("./system/Entry.js"),
    entryFacade: require("./system/entryFacade.js"),

    DatasourceAdapter: require("./system/DatasourceAdapter.js"),
    TextDatasource: require("./system/TextDatasource.js"),
    FileDatasource: require("./system/FileDatasource.js"),
    OwnCloudDatasource: require("./system/OwnCloudDatasource.js"),
    NextcloudDatasource: require("./system/NextcloudDatasource.js"),
    WebDAVDatasource: require("./system/WebDAVDatasource.js"),
    BoxDatasource: require("./system/BoxDatasource.js"),
    MyButtercupDatasource: require("./system/MyButtercupDatasource.js"),
    DropboxDatasource: require("./system/DropboxDatasource.js"),

    Flattener: require("./system/Flattener.js"),
    Descriptor: require("./system/Descriptor.js"),
    EntryFinder: require("./system/EntryFinder.js"),

    storage: {
        StorageInterface: require("./system/storage/StorageInterface.js"),
        MemoryStorageInterface: require("./system/storage/MemoryStorageInterface.js")
    },

    archiveManagement: {
        marshalling: require("./system/archiveManagement/marshalling.js")
    },

    tools: {
        encoding: require("./tools/encoding.js"),
        entry: require("./tools/entry.js"),
        export: require("./tools/export.js"),
        overrides: require("./tools/overridable.js"),
        signing: require("./tools/signing.js"),
        searching: {
            instance: require("./tools/searching-instance.js"),
            raw: require("./tools/searching-raw.js")
        }
    },

    vendor: {
        iocane,
        webdavFS
    }
};
<commit_msg>Add new archive manager to module index<commit_after>const iocane = require("iocane");
const webdavFS = require("webdav-fs");
const OriginalArchiveManager = require("./system/ArchiveManager.js");

OriginalArchiveManager.v2 = {
    ArchiveManager: require("./system/archiveManagement/ArchiveManager.js"),
    ArchiveSource: require("./system/archiveManagement/ArchiveSource.js")
};

module.exports = {
    Archive: require("./system/Archive.js"),
    ArchiveManager: OriginalArchiveManager,
    Westley: require("./system/Westley.js"),
    Inigo: require("./system/InigoGenerator.js"),
    Workspace: require("./system/Workspace.js"),

    createCredentials: require("./system/credentials.js"),
    Model: require("./system/Model.js"),

    Group: require("./system/Group.js"),
    Entry: require("./system/Entry.js"),
    entryFacade: require("./system/entryFacade.js"),

    DatasourceAdapter: require("./system/DatasourceAdapter.js"),
    TextDatasource: require("./system/TextDatasource.js"),
    FileDatasource: require("./system/FileDatasource.js"),
    OwnCloudDatasource: require("./system/OwnCloudDatasource.js"),
    NextcloudDatasource: require("./system/NextcloudDatasource.js"),
    WebDAVDatasource: require("./system/WebDAVDatasource.js"),
    BoxDatasource: require("./system/BoxDatasource.js"),
    MyButtercupDatasource: require("./system/MyButtercupDatasource.js"),
    DropboxDatasource: require("./system/DropboxDatasource.js"),

    Flattener: require("./system/Flattener.js"),
    Descriptor: require("./system/Descriptor.js"),
    EntryFinder: require("./system/EntryFinder.js"),

    storage: {
        StorageInterface: require("./system/storage/StorageInterface.js"),
        MemoryStorageInterface: require("./system/storage/MemoryStorageInterface.js")
    },

    archiveManagement: {
        marshalling: require("./system/archiveManagement/marshalling.js")
    },

    tools: {
        encoding: require("./tools/encoding.js"),
        entry: require("./tools/entry.js"),
        export: require("./tools/export.js"),
        overrides: require("./tools/overridable.js"),
        signing: require("./tools/signing.js"),
        searching: {
            instance: require("./tools/searching-instance.js"),
            raw: require("./tools/searching-raw.js")
        }
    },

    vendor: {
        iocane,
        webdavFS
    }
};
<|endoftext|>