<commit_before>const ROOM_NAME = "Shadow Ban Room";
var room = Rooms.get(toId(ROOM_NAME));
if (!room) {
	Rooms.global.addChatRoom(ROOM_NAME);
	room = Rooms.get(toId(ROOM_NAME));

	room.isPrivate = true;
	room.staffRoom = true;
	room.staffAutojoin = true;
	room.addedUsers = {};

	if (room.chatRoomData) {
		room.chatRoomData.isPrivate = true;
		room.chatRoomData.staffRoom = true;
		room.chatRoomData.staffAutojoin = true;
		room.chatRoomData.addedUsers = room.addedUsers;

		Rooms.global.writeChatRoomData();
	}
}
if (Object.size(room.addedUsers) > 0) {
	setImmediate(function () {
		room.add("||Loaded user list: " + Object.keys(room.addedUsers).sort().join(", "));
		room.update();
	});
}
exports.room = room;

function getAllAlts(user) {
	var targets = {};
	if (typeof user === 'string') {
		targets[toId(user)] = 1;
	} else {
		user.getAlts().concat(user.name).forEach(function (altName) {
			var alt = Users.get(altName);
			if (!alt.named) return;

			targets[toId(alt)] = 1;
			Object.keys(alt.prevNames).forEach(function (name) {
				targets[toId(name)] = 1;
			});
		});
	}
	return targets;
}

function intersectAndExclude(a, b) {
	var intersection = [];
	var exclusionA = [];
	var exclusionB = [];

	var ai = 0;
	var bi = 0;
	while (ai < a.length && bi < b.length) {
		var difference = a[ai].localeCompare(b[bi]);
		if (difference < 0) {
			exclusionA.push(a[ai]);
			++ai;
		} else if (difference > 0) {
			exclusionB.push(b[bi]);
			++bi;
		} else {
			intersection.push(a[ai]);
			++ai;
			++bi;
		}
	}

	Array.prototype.push.apply(exclusionA, a.slice(ai));
	Array.prototype.push.apply(exclusionB, b.slice(bi));
	return {intersection: intersection, exclusionA: exclusionA, exclusionB: exclusionB};
}

var checkBannedCache = {};
var checkBanned = exports.checkBanned = function (user) {
	var userId = toId(user);
	if (userId in checkBannedCache) return checkBannedCache[userId];
	//console.log("Shadow ban cache miss:", userId);

	var targets = Object.keys(getAllAlts(user)).sort();
	var bannedUsers = Object.keys(room.addedUsers).sort();

	var matches = intersectAndExclude(targets, bannedUsers);
	var isBanned = matches.intersection.length !== 0;
	for (var t = 0; t < targets.length; ++t) {
		if (isBanned) room.addedUsers[targets[t]] = 1;
		checkBannedCache[targets[t]] = isBanned;
	}
	if (!isBanned) return false;

	if (matches.exclusionA.length > 0) {
		Rooms.global.writeChatRoomData();
		room.add("||Alts of " + matches.intersection[0] + " automatically added: " + matches.exclusionA.join(", "));
	}

	return true;
};

var addUser = exports.addUser = function (user) {
	var targets = getAllAlts(user);
	for (var u in targets) {
		if (room.addedUsers[u]) {
			delete targets[u];
		} else {
			room.addedUsers[u] = 1;
		}
		checkBannedCache[u] = true;
	}
	targets = Object.keys(targets).sort();

	if (targets.length > 0) {
		Rooms.global.writeChatRoomData();
		room.add("||Added users: " + targets.join(", "));
		room.update();
	}

	return targets;
};
var removeUser = exports.removeUser = function (user) {
	var targets = getAllAlts(user);
	for (var u in targets) {
		if (!room.addedUsers[u]) {
			delete targets[u];
		} else {
			delete room.addedUsers[u];
		}
		checkBannedCache[u] = false;
	}
	targets = Object.keys(targets).sort();

	if (targets.length > 0) {
		Rooms.global.writeChatRoomData();
		room.add("||Removed users: " + targets.join(", "));
		room.update();
	}

	return targets;
};

var addMessage = exports.addMessage = function (user, tag, message) {
	room.add('|c|' + user.getIdentity() + '|__(' + tag + ')__ ' + message);
	room.update();
};

exports.commands = {
	spam: 'shadowban',
	sban: 'shadowban',
	shadowban: function (target, room, user) {
		if (!target) return this.sendReply("/shadowban OR /sban [username], [secondary command], [reason] - Sends all the user's messages to the shadow ban room.");

		var params = this.splitTarget(target).split(',');
		var action = params[0].trim().toLowerCase();
		var reason = params.slice(1).join(',').trim();
		if (!(action in CommandParser.commands)) {
			action = 'mute';
			reason = params.join(',').trim();
		}

		if (!this.targetUser) return this.sendReply("User '" + this.targetUsername + "' not found.");
		if (!this.can('lock', this.targetUser)) return;

		var targets = addUser(this.targetUser);
		if (targets.length === 0) {
			return this.sendReply('||' + this.targetUsername + " is already shadow banned or isn't named.");
		}
		this.privateModCommand("(" + user.name + " has shadow banned: " + targets.join(", ") + (reason ? " (" + reason + ")" : "") + ")");

		//return this.parse('/' + action + ' ' + toId(this.targetUser) + ',' + reason);
	},

	unspam: 'unshadowban',
	unsban: 'unshadowban',
	unshadowban: function (target, room, user) {
		if (!target) return this.sendReply("/unshadowban OR /unsban [username] - Undoes /shadowban (except the secondary command).");
		this.splitTarget(target);

		if (!this.can('lock')) return;

		var targets = removeUser(this.targetUser || this.targetUsername);
		if (targets.length === 0) {
			return this.sendReply('||' + this.targetUsername + " is not shadow banned.");
		}
		this.privateModCommand("(" + user.name + " has shadow unbanned: " + targets.join(", ") + ")");
	},

	sbanlist: function (target, room, user) {
		if (!target && !this.can('lock')) return this.sendReply("The command '/sbanlist' was unrecognized.  To send a message starting with '/sbanlist', type '//sbanlist'.");
		if ((user.locked || user.mutedRooms[room.id]) && !user.can('bypassall')) return this.sendReply("You cannot do this while unable to talk.");
		if (!this.can('lock')) return false;

		Users.get(toId(user.name)).send('|popup| Here is a list of sbanned users: \n' + JSON.stringify(Rooms.rooms.shadowbanroom.chatRoomData, null, 2));
	}
};

Users.ShadowBan = exports;
<commit_msg>Remove staff autojoin<commit_after>const ROOM_NAME = "Shadow Ban Room";
var room = Rooms.get(toId(ROOM_NAME));
if (!room) {
	Rooms.global.addChatRoom(ROOM_NAME);
	room = Rooms.get(toId(ROOM_NAME));

	room.isPrivate = true;
	room.staffRoom = true;
	room.addedUsers = {};

	if (room.chatRoomData) {
		room.chatRoomData.isPrivate = true;
		room.chatRoomData.staffRoom = true;
		room.chatRoomData.addedUsers = room.addedUsers;

		Rooms.global.writeChatRoomData();
	}
}
if (Object.size(room.addedUsers) > 0) {
	setImmediate(function () {
		room.add("||Loaded user list: " + Object.keys(room.addedUsers).sort().join(", "));
		room.update();
	});
}
exports.room = room;

function getAllAlts(user) {
	var targets = {};
	if (typeof user === 'string') {
		targets[toId(user)] = 1;
	} else {
		user.getAlts().concat(user.name).forEach(function (altName) {
			var alt = Users.get(altName);
			if (!alt.named) return;

			targets[toId(alt)] = 1;
			Object.keys(alt.prevNames).forEach(function (name) {
				targets[toId(name)] = 1;
			});
		});
	}
	return targets;
}

function intersectAndExclude(a, b) {
	var intersection = [];
	var exclusionA = [];
	var exclusionB = [];

	var ai = 0;
	var bi = 0;
	while (ai < a.length && bi < b.length) {
		var difference = a[ai].localeCompare(b[bi]);
		if (difference < 0) {
			exclusionA.push(a[ai]);
			++ai;
		} else if (difference > 0) {
			exclusionB.push(b[bi]);
			++bi;
		} else {
			intersection.push(a[ai]);
			++ai;
			++bi;
		}
	}

	Array.prototype.push.apply(exclusionA, a.slice(ai));
	Array.prototype.push.apply(exclusionB, b.slice(bi));
	return {intersection: intersection, exclusionA: exclusionA, exclusionB: exclusionB};
}

var checkBannedCache = {};
var checkBanned = exports.checkBanned = function (user) {
	var userId = toId(user);
	if (userId in checkBannedCache) return checkBannedCache[userId];
	//console.log("Shadow ban cache miss:", userId);

	var targets = Object.keys(getAllAlts(user)).sort();
	var bannedUsers = Object.keys(room.addedUsers).sort();

	var matches = intersectAndExclude(targets, bannedUsers);
	var isBanned = matches.intersection.length !== 0;
	for (var t = 0; t < targets.length; ++t) {
		if (isBanned) room.addedUsers[targets[t]] = 1;
		checkBannedCache[targets[t]] = isBanned;
	}
	if (!isBanned) return false;

	if (matches.exclusionA.length > 0) {
		Rooms.global.writeChatRoomData();
		room.add("||Alts of " + matches.intersection[0] + " automatically added: " + matches.exclusionA.join(", "));
	}

	return true;
};

var addUser = exports.addUser = function (user) {
	var targets = getAllAlts(user);
	for (var u in targets) {
		if (room.addedUsers[u]) {
			delete targets[u];
		} else {
			room.addedUsers[u] = 1;
		}
		checkBannedCache[u] = true;
	}
	targets = Object.keys(targets).sort();

	if (targets.length > 0) {
		Rooms.global.writeChatRoomData();
		room.add("||Added users: " + targets.join(", "));
		room.update();
	}

	return targets;
};
var removeUser = exports.removeUser = function (user) {
	var targets = getAllAlts(user);
	for (var u in targets) {
		if (!room.addedUsers[u]) {
			delete targets[u];
		} else {
			delete room.addedUsers[u];
		}
		checkBannedCache[u] = false;
	}
	targets = Object.keys(targets).sort();

	if (targets.length > 0) {
		Rooms.global.writeChatRoomData();
		room.add("||Removed users: " + targets.join(", "));
		room.update();
	}

	return targets;
};

var addMessage = exports.addMessage = function (user, tag, message) {
	room.add('|c|' + user.getIdentity() + '|__(' + tag + ')__ ' + message);
	room.update();
};

exports.commands = {
	spam: 'shadowban',
	sban: 'shadowban',
	shadowban: function (target, room, user) {
		if (!target) return this.sendReply("/shadowban OR /sban [username], [secondary command], [reason] - Sends all the user's messages to the shadow ban room.");

		var params = this.splitTarget(target).split(',');
		var action = params[0].trim().toLowerCase();
		var reason = params.slice(1).join(',').trim();
		if (!(action in CommandParser.commands)) {
			action = 'mute';
			reason = params.join(',').trim();
		}

		if (!this.targetUser) return this.sendReply("User '" + this.targetUsername + "' not found.");
		if (!this.can('lock', this.targetUser)) return;

		var targets = addUser(this.targetUser);
		if (targets.length === 0) {
			return this.sendReply('||' + this.targetUsername + " is already shadow banned or isn't named.");
		}
		this.privateModCommand("(" + user.name + " has shadow banned: " + targets.join(", ") + (reason ? " (" + reason + ")" : "") + ")");

		//return this.parse('/' + action + ' ' + toId(this.targetUser) + ',' + reason);
	},

	unspam: 'unshadowban',
	unsban: 'unshadowban',
	unshadowban: function (target, room, user) {
		if (!target) return this.sendReply("/unshadowban OR /unsban [username] - Undoes /shadowban (except the secondary command).");
		this.splitTarget(target);

		if (!this.can('lock')) return;

		var targets = removeUser(this.targetUser || this.targetUsername);
		if (targets.length === 0) {
			return this.sendReply('||' + this.targetUsername + " is not shadow banned.");
		}
		this.privateModCommand("(" + user.name + " has shadow unbanned: " + targets.join(", ") + ")");
	},

	sbanlist: function (target, room, user) {
		if (!target && !this.can('lock')) return this.sendReply("The command '/sbanlist' was unrecognized.  To send a message starting with '/sbanlist', type '//sbanlist'.");
		if ((user.locked || user.mutedRooms[room.id]) && !user.can('bypassall')) return this.sendReply("You cannot do this while unable to talk.");
		if (!this.can('lock')) return false;

		Users.get(toId(user.name)).send('|popup| Here is a list of sbanned users: \n' + JSON.stringify(Rooms.rooms.shadowbanroom.chatRoomData, null, 2));
	}
};

Users.ShadowBan = exports;
<|endoftext|>


<commit_before>
/**
 * Copyright (c) 2006
 * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/
if (!ORYX.Plugins)
    ORYX.Plugins = new Object();

ORYX.Plugins.File = Clazz.extend({

    facade: undefined,

	processURI: undefined,

    construct: function(facade){
        this.facade = facade;

        this.facade.offer({
            'name': "Save",
            'functionality': this.save.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/disk.png",
            'description': "Save",
            'index': 1,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Print",
            'functionality': this.print.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/printer.png",
            'description': "Print current modell",
            'index': 2,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Export as PDF",
            'functionality': this.exportPDF.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/page_white_acrobat.png",
            'description': "Export as PDF",
            'index': 3,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Info",
            'functionality': this.info.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/information.png",
            'description': "Info",
            'index': 4,
            'minShape': 0,
            'maxShape': 0
        });

		window.onbeforeunload = this.onUnLoad.bind(this)

		this.serializedDOM = DataManager.__persistDOM(this.facade);

    },

	onUnLoad: function(){

		if( this.serializedDOM != DataManager.__persistDOM(this.facade) ){

			return "There are unsaved data, please save before you leave, otherwise your changes get lost!";

		}

	},

    saveSynchronously: function(){

        //var resource = location.search.split("resource=");

		//Commented out because with Oles new server, this if check is true,
		// so it won't work.
		/*        if (resource.length == 1) {
	            // SAVE the DOM with ARESS-SERVER
	            DataManager.__syncglobal(this.facade);

        } else { */
            // SAVE the DOM with ORYX-SERVER
            //resource = resource[1].split("&")[0];

		// Get the serialized dom
		this.serializedDOM = DataManager.__persistDOM(this.facade);

		var reqURI = this.processURI ? this.processURI : location.href;

		// Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

		try{
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch(e) {}

        var svgDOM = DataManager.serialize(svgClone);

		// Check if this is the NEW URL
		if( reqURI.include( ORYX.CONFIG.ORYX_NEW_URL ) ){

			// Define Default values
			var defaultData = {title:'New Process', summary:'', type:'bpmn', url: reqURI}

			// Create a Template
			var dialog = new Ext.XTemplate(
						// TODO find some nice words here -- copy from above ;)
						'<form class="oryx_repository_edit_model" action="#" id="edit_model" onsubmit="return false;">',

							'<fieldset><legend>General Properties</legend>',
								'
These properties describe the model.
',

								'
Title<input type="text" class="text" name="title" value="{title}" id="edit_model_title" onfocus="this.className = \'text activated\'" onblur="this.className = \'text\'"/>
',
								'
Description<textarea rows="5" name="summary" id="edit_model_summary" onfocus="this.className = \'activated\'" onblur="this.className = \'\'">{summary}</textarea>
',
								'
Type<input type="text" name="type" class="text disabled" value="{type}" disabled="disabled" id="edit_model_type" />
',

							'</fieldset>',

						'</form>')

			// Create the callback for the template
			callback = function(form){

				var title 		= form.elements["title"].value.strip();
				title 			= title.length == 0 ? defaultData.title : title;

				var summary = form.elements["summary"].value.strip();
				summary 	= summary.length == 0 ? defaultData.summary : summary;

				var type 		= form.elements["type"].value.strip();
				type 			= type.length == 0 ? defaultData.type : type;

				win.hide();

				// Send the request out
				this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM, title: title, summary: summary, type: type } );

			}.bind(this);

			// Create a new window
			win = new Ext.Window({
				id:'Propertie_Window',
		        width:550,
		        height:244,
		        title:"Save as...",
		        modal:true,
		        html: dialog.apply( defaultData ),
				buttons:[{
					text: 'Save',
					handler: function(){
						callback( $('edit_model') )
					}
				},{
                	text: 'Close',
                	handler: function(){
                    	win.hide();
                	}
				}]
		    });

			win.show();

		} else {

			// Send the request out
			this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM } );

		}
    },

	sendSaveRequest: function(url, params){

		// Send the request to the server.
		new Ajax.Request(url, {
                method: 'POST',
                asynchronous: false,
                parameters: params,
			onSuccess: (function(transport) {
				var loc = transport.getResponseHeader("location");
				if (!this.processURI && loc) {
					this.processURI = loc;
				}

				//show saved status
				this.facade.raiseEvent({
						type:'loading.status',
						text:'Saved!'
					});
			}).bind(this),
			onFailure: function(transport) {
				// raise loading disable event.
                this.facade.raiseEvent({
                    type: 'loading.disable'
                });

				Ext.Msg.alert("Oryx", "Saving failed.");

				ORYX.log.warn("Saving failed: " + transport.responseText);
			}});

	},

    /**
     * Saves the current process to the server.
     * @param {Object} saveSynchronously when true, this call is synchronous and
     * waits for server reply. In this case, this call doesn't raise events for
     * loading plugin. If false, this will raise loading events and save
     * asynchronously. Use latter if UI responsibility is wanted, Former when
     * you need to be certain that saving is finished.
     */
    save: function(event, synchronously){

        // if not to saved synchronously
        if (synchronously == undefined) {

            // raise loading enable event
            this.facade.raiseEvent({
                type: 'loading.enable',
				text: 'Saving'
            });

            // asynchronously ...
            window.setTimeout((function(){

                // ... save synchronously
                this.saveSynchronously();

            }).bind(this), 10);

        }
        else

            // just save, synchronously.
            this.saveSynchronously();

        return true;
    },

    info: function(){

        //TODO Make this fit in 80 columns.
        var info = "Copyright (c) 2006\n" +
        "Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner\n\n" +
        "Permission is hereby granted, free of charge, to any person " +
        "obtaining a copy of this software and associated documentation files " +
        "(the Software), to deal in the Software without restriction, " +
        "including without limitation the rights to use, copy, modify, merge, " +
        "publish, distribute, sublicense, and/or sell copies of the Software, " +
        "and to permit persons to whom the Software is furnished to do so, " +
        "subject to the following conditions:\n\n" +
        "The above copyright notice and this permission notice shall be " +
        "included in all copies or substantial portions of the Software.\n\n" +
        "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " +
        "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " +
        "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " +
        "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS " +
        "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN " +
        "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " +
        "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE " +
        "SOFTWARE.";

        Ext.Msg.alert("Oryx", info);
        return false;
    },

    exportPDF: function(){

        var resource = location.href;

        // Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

        var svgDOM = DataManager.serialize(svgClone);

        // Send the svg to the server.
        //TODO make this better by using content negotiation instead of format parameter.
        //TODO make this better by generating svg on the server, too.
        new Ajax.Request(ORYX.CONFIG.PDF_EXPORT_URL, {
            method: 'POST',
            parameters: {
                resource: resource,
                data: svgDOM,
                format: "pdf"
            },
            onSuccess: function(request){

                // Because the pdf may be opened in the same window as the
                // process, yet the process may not have been saved, we're
                // opening every other representation in a new window.
                // location.href = request.responseText
                window.open(request.responseText);
            }
        });
    },

    print: function(){

        // Set all options for the new window
        var option = $H({
            width: 300,
            height: 400,
            toolbar: "no",
            status: "no",
            menubar: "yes",
            dependent: "yes",
            resizable: "yes",
            scrollbars: "yes"
        });

        // Create the new window with all the settings
        var newWindow = window.open("", "PrintWindow", option.invoke('join', '=').join(','));

        // Add a style tag to the head and hide all controls
        var head = newWindow.document.getElementsByTagName('head')[0];
        var style = document.createElement("style");
        style.innerHTML = " body {padding:0px; margin:0px} .svgcontainer { display:none; }";
        head.appendChild(style);

        // Clone the svg-node and append this to the new body
        newWindow.document.getElementsByTagName('body')[0].appendChild(this.facade.getCanvas().getRootNode().cloneNode(true));
        var svg = newWindow.document.getElementsByTagName('body')[0].getElementsByTagName('svg')[0];

        // Set the width and height
        svg.setAttributeNS(null, 'width', 1100);
        svg.setAttributeNS(null, 'height', 1400);

        // Set the correct size and rotation
        svg.lastChild.setAttributeNS(null, 'transform', 'scale(0.47, 0.47) rotate(270, 1510, 1470)');

        var markers = ['marker-start', 'marker-mid', 'marker-end']
        var path = $A(newWindow.document.getElementsByTagName('path'));
        path.each(function(pathNode){
            markers.each(function(marker){
                // Get the marker value
                var url = pathNode.getAttributeNS(null, marker);
                if (!url) {
                    return
                };

                // Replace the URL and set them new
                url = "url(about:blank#" + url.slice(5);
                pathNode.setAttributeNS(null, marker, url);
            });
        });

        // Get the print dialog
        newWindow.print();

        return true;
    }
});
<commit_msg>Changed that the sent type to the server is now the namespace<commit_after>
/**
 * Copyright (c) 2006
 * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/
if (!ORYX.Plugins)
    ORYX.Plugins = new Object();

ORYX.Plugins.File = Clazz.extend({

    facade: undefined,

	processURI: undefined,

    construct: function(facade){
        this.facade = facade;

        this.facade.offer({
            'name': "Save",
            'functionality': this.save.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/disk.png",
            'description': "Save",
            'index': 1,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Print",
            'functionality': this.print.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/printer.png",
            'description': "Print current modell",
            'index': 2,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Export as PDF",
            'functionality': this.exportPDF.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/page_white_acrobat.png",
            'description': "Export as PDF",
            'index': 3,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Info",
            'functionality': this.info.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/information.png",
            'description': "Info",
            'index': 4,
            'minShape': 0,
            'maxShape': 0
        });

		window.onbeforeunload = this.onUnLoad.bind(this)

		this.serializedDOM = DataManager.__persistDOM(this.facade);

    },

	onUnLoad: function(){

		if( this.serializedDOM != DataManager.__persistDOM(this.facade) ){

			return "There are unsaved data, please save before you leave, otherwise your changes get lost!";

		}

	},

    saveSynchronously: function(){

        //var resource = location.search.split("resource=");

		//Commented out because with Oles new server, this if check is true,
		// so it won't work.
		/*        if (resource.length == 1) {
	            // SAVE the DOM with ARESS-SERVER
	            DataManager.__syncglobal(this.facade);

        } else { */
            // SAVE the DOM with ORYX-SERVER
            //resource = resource[1].split("&")[0];

		// Get the serialized dom
		this.serializedDOM = DataManager.__persistDOM(this.facade);

		var reqURI = this.processURI ? this.processURI : location.href;

		// Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

		try{
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch(e) {}

        var svgDOM = DataManager.serialize(svgClone);

		// Check if this is the NEW URL
		if( reqURI.include( ORYX.CONFIG.ORYX_NEW_URL ) ){

			// Get the stencilset
			var ss = this.facade.getStencilSets().values()[0]

			// Define Default values
			var defaultData = {title:'New Process', summary:'', type:ss.title(), url: reqURI, namespace: ss.namespace() }

			// Create a Template
			var dialog = new Ext.XTemplate(
						// TODO find some nice words here -- copy from above ;)
						'<form class="oryx_repository_edit_model" action="#" id="edit_model" onsubmit="return false;">',

							'<fieldset><legend>General Properties</legend>',
								'
These properties describe the model.
',
								'<input type="hidden" name="namespace" value="{namespace}" />',
								'
Title<input type="text" class="text" name="title" value="{title}" id="edit_model_title" onfocus="this.className = \'text activated\'" onblur="this.className = \'text\'"/>
',
								'
Description<textarea rows="5" name="summary" id="edit_model_summary" onfocus="this.className = \'activated\'" onblur="this.className = \'\'">{summary}</textarea>
',
								'
Type<input type="text" name="type" class="text disabled" value="{type}" disabled="disabled" id="edit_model_type" />
',

							'</fieldset>',

						'</form>')

			// Create the callback for the template
			callback = function(form){

				var title 		= form.elements["title"].value.strip();
				title 			= title.length == 0 ? defaultData.title : title;

				var summary = form.elements["summary"].value.strip();
				summary 	= summary.length == 0 ? defaultData.summary : summary;

				var namespace	= form.elements["namespace"].value.strip();
				namespace		= type.length == 0 ? defaultData.namespace : namespace;

				win.hide();

				// Send the request out
				this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM, title: title, summary: summary, type: namespace } );

			}.bind(this);

			// Create a new window
			win = new Ext.Window({
				id:'Propertie_Window',
		        width:550,
		        height:244,
		        title:"Save as...",
		        modal:true,
		        html: dialog.apply( defaultData ),
				buttons:[{
					text: 'Save',
					handler: function(){
						callback( $('edit_model') )
					}
				},{
                	text: 'Close',
                	handler: function(){
                    	win.hide();
                	}
				}]
		    });

			win.show();

		} else {

			// Send the request out
			this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM } );

		}
    },

	sendSaveRequest: function(url, params){

		// Send the request to the server.
		new Ajax.Request(url, {
                method: 'POST',
                asynchronous: false,
                parameters: params,
			onSuccess: (function(transport) {
				var loc = transport.getResponseHeader("location");
				if (!this.processURI && loc) {
					this.processURI = loc;
				}

				//show saved status
				this.facade.raiseEvent({
						type:'loading.status',
						text:'Saved!'
					});
			}).bind(this),
			onFailure: function(transport) {
				// raise loading disable event.
                this.facade.raiseEvent({
                    type: 'loading.disable'
                });

				Ext.Msg.alert("Oryx", "Saving failed.");

				ORYX.log.warn("Saving failed: " + transport.responseText);
			}});

	},

    /**
     * Saves the current process to the server.
     * @param {Object} saveSynchronously when true, this call is synchronous and
     * waits for server reply. In this case, this call doesn't raise events for
     * loading plugin. If false, this will raise loading events and save
     * asynchronously. Use latter if UI responsibility is wanted, Former when
     * you need to be certain that saving is finished.
     */
    save: function(event, synchronously){

        // if not to saved synchronously
        if (synchronously == undefined) {

            // raise loading enable event
            this.facade.raiseEvent({
                type: 'loading.enable',
				text: 'Saving'
            });

            // asynchronously ...
            window.setTimeout((function(){

                // ... save synchronously
                this.saveSynchronously();

            }).bind(this), 10);

        }
        else

            // just save, synchronously.
            this.saveSynchronously();

        return true;
    },

    info: function(){

        //TODO Make this fit in 80 columns.
        var info = "Copyright (c) 2006\n" +
        "Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner\n\n" +
        "Permission is hereby granted, free of charge, to any person " +
        "obtaining a copy of this software and associated documentation files " +
        "(the Software), to deal in the Software without restriction, " +
        "including without limitation the rights to use, copy, modify, merge, " +
        "publish, distribute, sublicense, and/or sell copies of the Software, " +
        "and to permit persons to whom the Software is furnished to do so, " +
        "subject to the following conditions:\n\n" +
        "The above copyright notice and this permission notice shall be " +
        "included in all copies or substantial portions of the Software.\n\n" +
        "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " +
        "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " +
        "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " +
        "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS " +
        "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN " +
        "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " +
        "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE " +
        "SOFTWARE.";

        Ext.Msg.alert("Oryx", info);
        return false;
    },

    exportPDF: function(){

        var resource = location.href;

        // Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

        var svgDOM = DataManager.serialize(svgClone);

        // Send the svg to the server.
        //TODO make this better by using content negotiation instead of format parameter.
        //TODO make this better by generating svg on the server, too.
        new Ajax.Request(ORYX.CONFIG.PDF_EXPORT_URL, {
            method: 'POST',
            parameters: {
                resource: resource,
                data: svgDOM,
                format: "pdf"
            },
            onSuccess: function(request){

                // Because the pdf may be opened in the same window as the
                // process, yet the process may not have been saved, we're
                // opening every other representation in a new window.
                // location.href = request.responseText
                window.open(request.responseText);
            }
        });
    },

    print: function(){

        // Set all options for the new window
        var option = $H({
            width: 300,
            height: 400,
            toolbar: "no",
            status: "no",
            menubar: "yes",
            dependent: "yes",
            resizable: "yes",
            scrollbars: "yes"
        });

        // Create the new window with all the settings
        var newWindow = window.open("", "PrintWindow", option.invoke('join', '=').join(','));

        // Add a style tag to the head and hide all controls
        var head = newWindow.document.getElementsByTagName('head')[0];
        var style = document.createElement("style");
        style.innerHTML = " body {padding:0px; margin:0px} .svgcontainer { display:none; }";
        head.appendChild(style);

        // Clone the svg-node and append this to the new body
        newWindow.document.getElementsByTagName('body')[0].appendChild(this.facade.getCanvas().getRootNode().cloneNode(true));
        var svg = newWindow.document.getElementsByTagName('body')[0].getElementsByTagName('svg')[0];

        // Set the width and height
        svg.setAttributeNS(null, 'width', 1100);
        svg.setAttributeNS(null, 'height', 1400);

        // Set the correct size and rotation
        svg.lastChild.setAttributeNS(null, 'transform', 'scale(0.47, 0.47) rotate(270, 1510, 1470)');

        var markers = ['marker-start', 'marker-mid', 'marker-end']
        var path = $A(newWindow.document.getElementsByTagName('path'));
        path.each(function(pathNode){
            markers.each(function(marker){
                // Get the marker value
                var url = pathNode.getAttributeNS(null, marker);
                if (!url) {
                    return
                };

                // Replace the URL and set them new
                url = "url(about:blank#" + url.slice(5);
                pathNode.setAttributeNS(null, marker, url);
            });
        });

        // Get the print dialog
        newWindow.print();

        return true;
    }
});
<|endoftext|>


<commit_before>// Get the required shit together
const Discord = require('eris');
const config = require('config');
const utils = require('./utils.js');
require('colors');

const client = new Discord.Client(config.get('api').discord.token);
const prefixes = config.get('discord').prefix.user.concat(config.get('discord').prefix.guild);
let prefix = null;

// Setup commands and util objects.
const commands = require('./cogs.js');

client.on('shardReady', (id) => {
	console.log(`Shard ${id} is online`.green);
});

client.on('ready', () => {
	// Set up regex for the bot.
	// It's "man's essential illness"
	// Use this regex for testing in regexr.com
	// /^(mss).?(ping)\s?([\s\S]*)/
	// /(\w+)rly/
	prefix = new RegExp(`^(${prefixes.join('|')}).?(${Object.keys(commands).join('|')})\\s?([\\s\\S]*)`, 'i');

	// Add mentions to the prefix list
	prefixes.push(`<@${client.user.id}>`);
	console.log('All shards are online'.green.bold);

	// Set up currently playing game
	client.editStatus('online', {
		name: `${prefixes[0]} help`,
		type: 0,
		url: config.get('api').mailgun.domain
	});

	// Send DBOTS info if it was provided.
	if (config.get('api').botsdiscordpw) {
		utils.botsdiscordpw(client);
		setInterval(() => {
			utils.botsdiscordpw(client);
		}, 1800000);
	}

	// Send FAKEDBOTS info if it was provided.
	if (config.get('api').discordbotsorg) {
		utils.discordbotsorg(client);
		setInterval(() => {
			utils.discordbotsorg(client);
		}, 1800000);
	}

	// Check for bot collection servers
	utils.collection.check(client);
	setInterval(() => {
		utils.collection.check(client);
	}, 1800000);

	client.on('messageCreate', (message) => {
		// It crashed on this before. No explaination.
		if (!message.author) return;
		// Disallow if the author is a bot
		if (message.author.bot) return;

		// Test the message content on the regular expression for prefixed commands.
		const pre = prefix.exec(message.content);

		// If there's a result, do this crap.
		if (pre) {
			message.prefix = pre[1];
			message.command = pre[2];
			message.input = pre[3] || null;
			message.name = message.author.username.replace(/ /g, '+')
				.replace(/\W/g, '=')
				.toLowerCase();
			message.context = config.get('discord').prefix.user.includes(message.prefix.toLowerCase()) ? 'user' : 'guild';
			message.inbox = message.context === 'user' ? message.author.id : (message.channel.guild && message.channel.guild.id) || 'Not inside a guild';

			// Run the actual command
			commands[message.command.toLowerCase()].command(message, client);
		}
	});
});

client.connect();
module.exports = client;
<commit_msg>Move name to email to dmail utils<commit_after>// Get the required shit together
const Discord = require('eris');
const config = require('config');
const utils = require('./utils.js');
require('colors');

const client = new Discord.Client(config.get('api').discord.token);
const prefixes = config.get('discord').prefix.user.concat(config.get('discord').prefix.guild);
let prefix = null;

// Setup commands and util objects.
const commands = require('./cogs.js');

client.on('shardReady', (id) => {
	console.log(`Shard ${id} is online`.green);
});

client.on('ready', () => {
	// Set up regex for the bot.
	// It's "man's essential illness"
	// Use this regex for testing in regexr.com
	// /^(mss).?(ping)\s?([\s\S]*)/
	// /(\w+)rly/
	prefix = new RegExp(`^(${prefixes.join('|')}).?(${Object.keys(commands).join('|')})\\s?([\\s\\S]*)`, 'i');

	// Add mentions to the prefix list
	prefixes.push(`<@${client.user.id}>`);
	console.log('All shards are online'.green.bold);

	// Set up currently playing game
	client.editStatus('online', {
		name: `${prefixes[0]} help`,
		type: 0,
		url: config.get('api').mailgun.domain
	});

	// Send DBOTS info if it was provided.
	if (config.get('api').botsdiscordpw) {
		utils.botsdiscordpw(client);
		setInterval(() => {
			utils.botsdiscordpw(client);
		}, 1800000);
	}

	// Send FAKEDBOTS info if it was provided.
	if (config.get('api').discordbotsorg) {
		utils.discordbotsorg(client);
		setInterval(() => {
			utils.discordbotsorg(client);
		}, 1800000);
	}

	// Check for bot collection servers
	utils.collection.check(client);
	setInterval(() => {
		utils.collection.check(client);
	}, 1800000);

	client.on('messageCreate', (message) => {
		// It crashed on this before. No explaination.
		if (!message.author) return;
		// Disallow if the author is a bot
		if (message.author.bot) return;

		// Test the message content on the regular expression for prefixed commands.
		const pre = prefix.exec(message.content);

		// If there's a result, do this crap.
		if (pre) {
			message.prefix = pre[1];
			message.command = pre[2];
			message.input = pre[3] || null;
			message.name = utils.dmail.name(message.author.username);
			message.context = config.get('discord').prefix.user.includes(message.prefix.toLowerCase()) ? 'user' : 'guild';
			message.inbox = message.context === 'user' ? message.author.id : (message.channel.guild && message.channel.guild.id) || 'Not inside a guild';

			// Run the actual command
			commands[message.command.toLowerCase()].command(message, client);
		}
	});
});

client.connect();
module.exports = client;
<|endoftext|>


<commit_before>import { resolve, dirname } from 'path'
import { createWriteStream } from 'fs'
import { start as startREPL } from 'repl'

import { percent, time, binary, prettyStringifyJSON } from 'source/common/format.js'
import { createStepper } from 'source/common/time.js'
import { isObjectAlike } from 'source/common/check.js'
import { basicArray } from 'source/common/verify.js'
import { throttle } from 'source/common/function.js'

import { writeBufferToStreamAsync, quickRunletFromStream } from 'source/node/data/Stream.js'
import { readBuffer, writeBuffer, readText } from 'source/node/fs/File.js'
import { configurePid } from 'source/node/module/Pid.js'
import { fetchWithJumpProxy } from 'source/node/module/Software/npm.js'

// HACK: add `@dr-js/core` to internal `modulePaths` to allow require
// code: https://github.com/nodejs/node/blob/v12.11.1/lib/internal/modules/cjs/loader.js#L620
//   > $ dr-js -e "console.log(module.filename)"
//   >   .../npm/node_modules/@dr-js/core/bin/function.js
//   > $ npx @dr-js/core -e "console.log(module.filename)"
//   >   .../.npm/_npx/####/lib/node_modules/@dr-js/core/bin/function.js
// and:
//   `.../npm/node_modules/@dr-js/*/bin/function.js` + `../../../../` = `.../npm/node_modules/` // allow this and related module to resolve
//   `.../.npm/_npx/####/lib/node_modules/@dr-js/*/bin/function.js` + `../../../../` = `.../.npm/_npx/####/lib/node_modules/` // allow this and related module to resolve
// NOTE:
//   currently for the `output-gitignore` code, output of `require('@dr-js/core/package.json').version` will be
//   the version from `./node_modules/@dr-js/core/package.json`, since it's higher in the path list,
//   and the '../../../../' will result in an invalid path
const modulePathHack = (newPath) => {
  if (!newPath.endsWith('node_modules')) return // keep only valid paths
  const modulePaths = require('module')._resolveLookupPaths('modulePaths') // list of path to look for global node_modules, check the value of `module.paths` in repl
  basicArray(modulePaths)
  if (!modulePaths.includes(newPath)) modulePaths.push(newPath)
}
const patchModulePath = () => modulePathHack(resolve(module.filename, '../../../../'))

const evalScript = ( // NOTE: use eval not Function to derive local
  evalScriptString, // inputFile ? String(readFileSync(inputFile)) : argumentList[ 0 ]
  evalScriptPath, // inputFile || resolve('__SCRIPT_STRING__'),
  evalArgv, // inputFile ? argumentList : argumentList.slice(1)
  evalOption // optionData
) => eval(`async (evalArgv, evalOption, __filename, __dirname, require) => { ${evalScriptString} }`)( // eslint-disable-line no-eval
  evalArgv, // NOTE: allow both evalArgv / argumentList is accessible from eval
  evalOption,
  evalScriptPath,
  dirname(evalScriptPath),
  require('module').createRequire(evalScriptPath)
)

const stepper = createStepper()
const logAuto = (...args) => console.log(
  ...((args.length === 1 && isObjectAlike(args[ 0 ]))
    ? [ JSON.stringify(args[ 0 ], null, 2) ]
    : args),
  `(+${time(stepper())})`
)

const sharedOption = (optionData, modeName) => {
  const { tryGet, tryGetFirst, getToggle } = optionData

  const log = getToggle('quiet') ? () => {} : logAuto

  const argumentList = tryGet(modeName) || []
  const inputFile = tryGetFirst('input-file')
  const outputFile = tryGetFirst('output-file')

  configurePid({ filePid: tryGetFirst('pid-file') })

  const autoBuffer = (value) => Buffer.isBuffer(value) ? value
    : isObjectAlike(value) ? JSON.stringify(value, null, 2) + '\n' // JSON String
      : `${value}\n` // should be String
  const outputValueAuto = async (value) => outputFile
    ? writeBuffer(outputFile, autoBuffer(value))
    : writeBufferToStreamAsync(process.stdout, autoBuffer(value))
  const outputStream = (stream) => quickRunletFromStream(
    stream,
    outputFile ? createWriteStream(outputFile) : process.stdout
  )

  return { // sharedPack
    optionData, modeName,
    argumentList, log, inputFile, outputFile, outputValueAuto, outputStream
  }
}

// NOTE: for `@dr-js/dev` to reuse & extend
const sharedMode = async ({
  // sharedPack
  optionData, modeName,
  argumentList, log, inputFile, outputValueAuto, outputStream,

  // patchModulePath overwrite, so more patch path can be added
  patchMP = patchModulePath,

  fetchUserAgent, fetchExtraOption, // TODO: DEPRECATE: no need to share
  fetchUA = fetchUserAgent // TODO: DEPRECATE: no need to share
}) => {
  switch (modeName) {
    case 'eval': {
      await patchMP()
      const result = await evalScript(
        inputFile ? await readText(inputFile) : argumentList[ 0 ],
        inputFile || resolve('__SCRIPT_STRING__'),
        inputFile ? argumentList : argumentList.slice(1),
        optionData
      )
      return result !== undefined && outputValueAuto(result)
    }
    case 'repl':
      await patchMP()
      return startREPL({ useGlobal: true }) // NOTE: need manual Ctrl+C

    case 'fetch': { // TODO: DEPRECATE: no need to share
      let [ initialUrl, method = 'GET', jumpMax = 4, timeout = 0 ] = argumentList
      jumpMax = Number(jumpMax) || 0 // 0 for no jump, use 'Infinity' for unlimited jump
      timeout = Number(timeout || optionData.tryGetFirst('timeout')) || 0 // in msec, 0 for unlimited // TODO: DEPRECATE: timeout from argumentList
      log(`[fetch] jumpMax: ${jumpMax}, timeout: ${timeout || 'none'}`)
      const body = inputFile ? await readBuffer(inputFile) : null
      let isDone = false
      const response = await fetchWithJumpProxy(initialUrl, {
        method, timeout, jumpMax, body,
        headers: { 'accept': '*/*', 'user-agent': fetchUA }, // patch for sites require a UA, like GitHub
        onProgressUpload: throttle((now, total) => isDone || log(`[fetch-upload] ${percent(now / total)} (${binary(now)}B / ${binary(total)}B)`), 1000),
        onProgressDownload: throttle((now, total) => isDone || log(`[fetch-download] ${percent(now / total)} (${binary(now)}B / ${binary(total)}B)`), 1000),
        preFetch: (url, jumpCount, cookieList) => log(`[fetch] <${method}>${url}, jump: ${jumpCount}/${jumpMax}, timeout: ${timeout ? time(timeout) : 'none'}, cookie: ${cookieList.length}`),
        ...fetchExtraOption
      })
      if (!response.ok) throw new Error(`bad status: ${response.status}`)
      const contentLength = Number(response.headers[ 'content-length' ])
      log(`[fetch] status: ${response.status}, header: ${prettyStringifyJSON(response.headers)}`)
      log(`[fetch] fetch response content${contentLength ? ` (${binary(contentLength)}B)` : ''}...`)
      await outputStream(response.stream())
      isDone = true
      return log('\n[fetch] done')
    }
  }
}

export { // NOTE: only borrow script from here for test or for another bin/script, will cause bloat if webpack pull code from both module/library
  modulePathHack, patchModulePath,
  evalScript,

  logAuto,
  sharedOption, sharedMode
}
<commit_msg>CHG: bin: use indirect eval for `evalScript`<commit_after>import { resolve, dirname } from 'path'
import { createWriteStream } from 'fs'
import { start as startREPL } from 'repl'

import { percent, time, binary, prettyStringifyJSON } from 'source/common/format.js'
import { createStepper } from 'source/common/time.js'
import { isObjectAlike } from 'source/common/check.js'
import { basicArray } from 'source/common/verify.js'
import { throttle } from 'source/common/function.js'

import { writeBufferToStreamAsync, quickRunletFromStream } from 'source/node/data/Stream.js'
import { readBuffer, writeBuffer, readText } from 'source/node/fs/File.js'
import { configurePid } from 'source/node/module/Pid.js'
import { fetchWithJumpProxy } from 'source/node/module/Software/npm.js'

// HACK: add `@dr-js/core` to internal `modulePaths` to allow require
// code: https://github.com/nodejs/node/blob/v12.11.1/lib/internal/modules/cjs/loader.js#L620
//   > $ dr-js -e "console.log(module.filename)"
//   >   .../npm/node_modules/@dr-js/core/bin/function.js
//   > $ npx @dr-js/core -e "console.log(module.filename)"
//   >   .../.npm/_npx/####/lib/node_modules/@dr-js/core/bin/function.js
// and:
//   `.../npm/node_modules/@dr-js/*/bin/function.js` + `../../../../` = `.../npm/node_modules/` // allow this and related module to resolve
//   `.../.npm/_npx/####/lib/node_modules/@dr-js/*/bin/function.js` + `../../../../` = `.../.npm/_npx/####/lib/node_modules/` // allow this and related module to resolve
// NOTE:
//   currently for the `output-gitignore` code, output of `require('@dr-js/core/package.json').version` will be
//   the version from `./node_modules/@dr-js/core/package.json`, since it's higher in the path list,
//   and the '../../../../' will result in an invalid path
const modulePathHack = (newPath) => {
  if (!newPath.endsWith('node_modules')) return // keep only valid paths
  const modulePaths = require('module')._resolveLookupPaths('modulePaths') // list of path to look for global node_modules, check the value of `module.paths` in repl
  basicArray(modulePaths)
  if (!modulePaths.includes(newPath)) modulePaths.push(newPath)
}
const patchModulePath = () => modulePathHack(resolve(module.filename, '../../../../'))

const evalScript = (
  evalScriptString, // inputFile ? String(readFileSync(inputFile)) : argumentList[ 0 ]
  evalScriptPath, // inputFile || resolve('__SCRIPT_STRING__'),
  evalArgv, // inputFile ? argumentList : argumentList.slice(1)
  evalOption // optionData
) => { // NOTE: use indirect eval to limit inner-context, check: https://esbuild.github.io/content-types/#direct-eval
  const asyncFunc = (0, eval)(`async (evalArgv, evalOption, __filename, __dirname, require) => { ${evalScriptString} }`) // eslint-disable-line no-eval
  return asyncFunc(evalArgv, evalOption, evalScriptPath, dirname(evalScriptPath), require('module').createRequire(evalScriptPath))
}

const stepper = createStepper()
const logAuto = (...args) => console.log(
  ...((args.length === 1 && isObjectAlike(args[ 0 ]))
    ? [ JSON.stringify(args[ 0 ], null, 2) ]
    : args),
  `(+${time(stepper())})`
)

const sharedOption = (optionData, modeName) => {
  const { tryGet, tryGetFirst, getToggle } = optionData

  const log = getToggle('quiet') ? () => {} : logAuto

  const argumentList = tryGet(modeName) || []
  const inputFile = tryGetFirst('input-file')
  const outputFile = tryGetFirst('output-file')

  configurePid({ filePid: tryGetFirst('pid-file') })

  const autoBuffer = (value) => Buffer.isBuffer(value) ? value
    : isObjectAlike(value) ? JSON.stringify(value, null, 2) + '\n' // JSON String
      : `${value}\n` // should be String
  const outputValueAuto = async (value) => outputFile
    ? writeBuffer(outputFile, autoBuffer(value))
    : writeBufferToStreamAsync(process.stdout, autoBuffer(value))
  const outputStream = (stream) => quickRunletFromStream(
    stream,
    outputFile ? createWriteStream(outputFile) : process.stdout
  )

  return { // sharedPack
    optionData, modeName,
    argumentList, log, inputFile, outputFile, outputValueAuto, outputStream
  }
}

// NOTE: for `@dr-js/dev` to reuse & extend
const sharedMode = async ({
  // sharedPack
  optionData, modeName,
  argumentList, log, inputFile, outputValueAuto, outputStream,

  // patchModulePath overwrite, so more patch path can be added
  patchMP = patchModulePath,

  fetchUserAgent, fetchExtraOption, // TODO: DEPRECATE: no need to share
  fetchUA = fetchUserAgent // TODO: DEPRECATE: no need to share
}) => {
  switch (modeName) {
    case 'eval': {
      await patchMP()
      const result = await evalScript(
        inputFile ? await readText(inputFile) : argumentList[ 0 ],
        inputFile || resolve('__SCRIPT_STRING__'),
        inputFile ? argumentList : argumentList.slice(1),
        optionData
      )
      return result !== undefined && outputValueAuto(result)
    }
    case 'repl':
      await patchMP()
      return startREPL({ useGlobal: true }) // NOTE: need manual Ctrl+C

    case 'fetch': { // TODO: DEPRECATE: no need to share
      let [ initialUrl, method = 'GET', jumpMax = 4, timeout = 0 ] = argumentList
      jumpMax = Number(jumpMax) || 0 // 0 for no jump, use 'Infinity' for unlimited jump
      timeout = Number(timeout || optionData.tryGetFirst('timeout')) || 0 // in msec, 0 for unlimited // TODO: DEPRECATE: timeout from argumentList
      log(`[fetch] jumpMax: ${jumpMax}, timeout: ${timeout || 'none'}`)
      const body = inputFile ? await readBuffer(inputFile) : null
      let isDone = false
      const response = await fetchWithJumpProxy(initialUrl, {
        method, timeout, jumpMax, body,
        headers: { 'accept': '*/*', 'user-agent': fetchUA }, // patch for sites require a UA, like GitHub
        onProgressUpload: throttle((now, total) => isDone || log(`[fetch-upload] ${percent(now / total)} (${binary(now)}B / ${binary(total)}B)`), 1000),
        onProgressDownload: throttle((now, total) => isDone || log(`[fetch-download] ${percent(now / total)} (${binary(now)}B / ${binary(total)}B)`), 1000),
        preFetch: (url, jumpCount, cookieList) => log(`[fetch] <${method}>${url}, jump: ${jumpCount}/${jumpMax}, timeout: ${timeout ? time(timeout) : 'none'}, cookie: ${cookieList.length}`),
        ...fetchExtraOption
      })
      if (!response.ok) throw new Error(`bad status: ${response.status}`)
      const contentLength = Number(response.headers[ 'content-length' ])
      log(`[fetch] status: ${response.status}, header: ${prettyStringifyJSON(response.headers)}`)
      log(`[fetch] fetch response content${contentLength ? ` (${binary(contentLength)}B)` : ''}...`)
      await outputStream(response.stream())
      isDone = true
      return log('\n[fetch] done')
    }
  }
}

export { // NOTE: only borrow script from here for test or for another bin/script, will cause bloat if webpack pull code from both module/library
  modulePathHack, patchModulePath,
  evalScript,

  logAuto,
  sharedOption, sharedMode
}
<|endoftext|>


<commit_before>var tableXSLTProcessor, listXSLTProcessor;

/** Add XML files to local storage. */
$( "#add-files" ).change(function(evt) {
    showLoading();
    var files = evt.target.files;
    var uniqueFilenames = $('#unique-fn').val() == 'True';
    var pending = files.length;

    for (var i = 0, f; f = files[i]; i++) {
        if (f.type !== 'text/xml') {
            showAlert(f.name + ' is not a valid XML file', 'warning');
            continue;
        }

        var reader = new FileReader();
            reader.onload = (function(theFile) {
                return function(e) {

                // Check for uniqueness
                var key = theFile.name;
                if (localStorage.getItem(theFile.name) && uniqueFilenames) {
                    showAlert('A file with the name ' + theFile.name + ' has \
                              already been uploaded.', 'warning');
                } else if (!uniqueFilenames) {
                    key += Date.now();
                }

                try {
                    //Remove XML declaration (for merging) and store
                    var xmlStr = e.target.result.replace(/<\?xml.*?\?>/g, "");
                    localStorage.setItem(key, xmlStr);
                } catch (e) {
                    showAlert(e, 'danger');
                }

                --pending
                if (pending == 0) {
                    refreshViews();
                }
            };
        })(f);
        reader.readAsText(f);
    }
});

/** Show loading icon. */
function showLoading() {
    $('#files-uploaded').hide();
    $('#loading-icon').show();
}

/** Hide loading icon. */
function hideLoading() {
    $('#loading-icon').hide();
    $('#files-uploaded').show();
}

/** Refresh the table and list views. */
function refreshViews() {
    var mergedDocs = mergeUploadedDocs();
    if (typeof tableXSLTProcessor == "undefined" ||
        typeof listXSLTProcessor == "undefined") {
        showAlert('XSLT processors not loaded yet, please try again.', 'warning');
    } else {
        var tableDoc = tableXSLTProcessor.transformToFragment(mergedDocs, document);
        var listDoc = listXSLTProcessor.transformToFragment(mergedDocs, document);
        $('#table-view').html(tableDoc);
        $('#list-view').html(listDoc);
    }
    $('#files-uploaded').html(localStorage.length + ' files uploaded');
    $('#tei-form').trigger("reset");
    enableSettings();
    hideLoading();
}

/** Enable or disable settings certain settings if local storage is empty. */
function enableSettings() {
    if (localStorage.length == 0){
        $('#unique-fn').attr('disabled', false);
        $('#default-settings').attr('disabled', false);
    } else {
        $('#unique-fn').attr('disabled', true);
        $('#default-settings').attr('disabled', true);
    }
    $('#unique-fn').selectpicker('refresh');
}

/** Return all uploaded files merged into single XML document. */
function mergeUploadedDocs(){
    var xmlStr, values = [], keys = Object.keys(localStorage), i = keys.length;
    while ( i-- ) {
        values.push(localStorage.getItem(keys[i]));
    }
    xmlStr = '<MERGED-TEI>' + values.join("") + '</MERGED-TEI>';
    return loadXMLDoc(xmlStr);
}

/** Display a Bootstrap alert. */
function showAlert(msg, type) {
    $( "#alerts" ).load( "_alerts.html #alert-template" ,function(){
        var template = $('#alert-template').html();
        var rendered = Mustache.render(template, {msg: msg, type: type});
        $('#alert-template').remove();
        $( "#alerts" ).append(rendered);
    });
}

/** Clear local storage and refresh views. */
$( "#clear-views" ).click(function() {
    showLoading();
    localStorage.clear();
    refreshViews();
});

/** Refresh the current XSLT processors. */
function refreshXSLTProcessors() {
    var tableXSLT = $('#select-table-xslt').val();
    var listXSLT = $('#select-list-xslt').val();

    // Load the table XSLT
    var tablePromise = Promise.resolve($.ajax({
        url: "assets/xsl/" + tableXSLT
    })).then(function(result) {
        tableXSLTProcessor = new XSLTProcessor();
        tableXSLTProcessor.importStylesheet(result);

        //Then load the list XSLT
        var listPromise = Promise.resolve($.ajax({
            url: "assets/xsl/" + listXSLT
        })).then(function(result) {
            listXSLTProcessor = new XSLTProcessor();
            listXSLTProcessor.importStylesheet(result);
            refreshViews();
        }, function() {
            showAlert(listXSLT + ' could not be loaded', 'danger');
        });
    }, function() {
        showAlert(tableXSLT + ' could not be loaded', 'danger');
    });
}

/** Export the table to CSV. */
$( "#csv-export" ).click(function() {
    // Return an escaped CSV string
    function formatCSV(str) {
        return escapedStr = '"' + str.replace(/"/g, '""') + '"';
    }

    // Get table rows
    var rows = [];
    $('table tr').each(function() {
        var row = [];
        $(this).find('th,td').each(function () {
            var val = $(this)[0].innerHTML;
            row.push(val)
        });
        rows.push(row.join(','));
    });

    var csvString = rows.join("\n");
    console.log(csvString);
    var encodedUri = encodeURI('data:attachment/csv;charset=utf-8,' + csvString);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "tei_data.csv");
    link.click();
});

/** Load and return an XML document. */
function loadXMLDoc(text) {
    var parseXml;
    if (typeof window.DOMParser != "undefined") {
        parseXml = function(xmlStr) {
            return (new window.DOMParser()).parseFromString(xmlStr, "text/xml");
        };
    } else if (typeof window.ActiveXObject != "undefined" &&
        new window.ActiveXObject("Microsoft.XMLDOM")) {
        parseXml = function(xmlStr) {
            var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = "false";
            xmlDoc.loadXML(xmlStr);
            return xmlDoc;
        };
    } else {
        var msg = "No XML parser found";
        showAlert(msg, 'danger')
        throw new Error(msg);
    }
    return parseXml(text);
}

//Function to convert boolean to capitalized string
Boolean.prototype.toCapsString = function () {
    return this.toString().charAt(0).toUpperCase() + this.toString().slice(1);
}

/** Reset to default settings. */
$( "#default-settings" ).click(function() {
    loadDefaultSettings();
});

/** Handle change of load table XSLT setting. */
$( "#select-table-xslt" ).change(function() {
    showLoading();
    var settings = Cookies.getJSON('settings');
    settings.xsl.selectedTable = $('#select-table-xslt').val();
    Cookies.set('settings', settings);
    refreshXSLTProcessors();
});

/** Handle change of load list XSLT setting. */
$( "#select-list-xslt" ).change(function() {
    showLoading();
    var settings = Cookies.getJSON('settings');
    settings.xsl.selectedList = $('#select-list-xslt').val();
    Cookies.set('settings', settings);
    refreshXSLTProcessors();
});

/** Handle change of unique filenames setting. */
$( "#unique-fn" ).change(function() {
    var settings = Cookies.getJSON('settings');
    var uniqueFn = $('#unique-fn').val() == 'True';
    settings.uniqueFilenames = uniqueFn;
    Cookies.set('settings', settings);
    console.log(Cookies.get('settings'));
});

/** Load settings from cookie. */
function loadSettings(){
    var settings = Cookies.getJSON('settings');

    // XSLT files
    $.each( settings.xsl.table, function( key, val ) {
        var html = '<option value="' + val + '">' + key + '</option>';
        $('#select-table-xslt').append(html);
    });
    $.each( settings.xsl.list, function( key, val ) {
        var html = '<option value="' + val + '">' + key + '</option>';
        $('#select-list-xslt').append(html);
    });
    $('#select-table-xslt').val(settings.xsl.selectedTable);
    $('#select-list-xslt').val(settings.xsl.selectedList);

    // Unique filenames
    var uniqueFn = settings.uniqueFilenames.toCapsString()
    $('#unique-fn').val(uniqueFn);

    $('.selectpicker').selectpicker('refresh');
    refreshXSLTProcessors();
}

/** Reset to default settings. */
function loadDefaultSettings() {
    $.getJSON( "settings.json", function( settings ) {
        Cookies.set('settings', settings);
        loadSettings();
    }).then(function() {
        refreshXSLTProcessors();
    }, function() {
        showAlert('A valid settings file could not be found', 'danger')
    });
}

$(function() {
    showLoading();

    // Check for required HTML5 features
    if (typeof(localStorage) == 'undefined' ) {
        showAlert('Your browser does not support HTML5 localStorage. \
                  Try upgrading.', 'danger');
    }
    if (typeof(FileReader) == 'undefined' || typeof(File) == 'undefined'
        || typeof(FileList) == 'undefined' || typeof(Blob) == 'undefined') {
        showAlert('Your browser does not support the HTML5 File APIs. \
                  Try upgrading.', 'danger');
    }

    // Initialise settings from cookie or defaults
    if (typeof Cookies.get('settings') != "undefined") {
        loadSettings();
    } else {
        loadDefaultSettings();
    }
});
<commit_msg>Improve error message<commit_after>var tableXSLTProcessor, listXSLTProcessor;

/** Add XML files to local storage. */
$( "#add-files" ).change(function(evt) {
    showLoading();
    var files = evt.target.files;
    var uniqueFilenames = $('#unique-fn').val() == 'True';
    var pending = files.length;

    for (var i = 0, f; f = files[i]; i++) {
        if (f.type !== 'text/xml') {
            showAlert(f.name + ' is not a valid XML file', 'warning');
            continue;
        }

        var reader = new FileReader();
            reader.onload = (function(theFile) {
                return function(e) {

                // Check for uniqueness
                var key = theFile.name;
                if (localStorage.getItem(theFile.name) && uniqueFilenames) {
                    showAlert('A file with the name ' + theFile.name + ' has \
                              already been uploaded.', 'warning');
                } else if (!uniqueFilenames) {
                    key += Date.now();
                }

                try {
                    //Remove XML declaration (for merging) and store
                    var xmlStr = e.target.result.replace(/<\?xml.*?\?>/g, "");
                    localStorage.setItem(key, xmlStr);
                } catch (e) {
                    showAlert("Upload failed, local storage quota \
                              exceeded. The currently loaded files must be \
                              cleared before more can be uploaded.", 'danger');
                    throw new Error(e)
                }

                --pending
                if (pending == 0) {
                    refreshViews();
                }
            };
        })(f);
        reader.readAsText(f);
    }
});

/** Show loading icon. */
function showLoading() {
    $('#files-uploaded').hide();
    $('#loading-icon').show();
}

/** Hide loading icon. */
function hideLoading() {
    $('#loading-icon').hide();
    $('#files-uploaded').show();
}

/** Refresh the table and list views. */
function refreshViews() {
    var mergedDocs = mergeUploadedDocs();
    if (typeof tableXSLTProcessor == "undefined" ||
        typeof listXSLTProcessor == "undefined") {
        showAlert('XSLT processors not loaded yet, please try again.', 'warning');
    } else {
        var tableDoc = tableXSLTProcessor.transformToFragment(mergedDocs, document);
        var listDoc = listXSLTProcessor.transformToFragment(mergedDocs, document);
        $('#table-view').html(tableDoc);
        $('#list-view').html(listDoc);
    }
    $('#files-uploaded').html(localStorage.length + ' files uploaded');
    $('#tei-form').trigger("reset");
    enableSettings();
    hideLoading();
}

/** Enable or disable settings certain settings if local storage is empty. */
function enableSettings() {
    if (localStorage.length == 0){
        $('#unique-fn').attr('disabled', false);
        $('#default-settings').attr('disabled', false);
    } else {
        $('#unique-fn').attr('disabled', true);
        $('#default-settings').attr('disabled', true);
    }
    $('#unique-fn').selectpicker('refresh');
}

/** Return all uploaded files merged into single XML document. */
function mergeUploadedDocs(){
    var xmlStr, values = [], keys = Object.keys(localStorage), i = keys.length;
    while ( i-- ) {
        values.push(localStorage.getItem(keys[i]));
    }
    xmlStr = '<MERGED-TEI>' + values.join("") + '</MERGED-TEI>';
    return loadXMLDoc(xmlStr);
}

/** Display a Bootstrap alert. */
function showAlert(msg, type) {
    $( "#alerts" ).load( "_alerts.html #alert-template" ,function(){
        var template = $('#alert-template').html();
        var rendered = Mustache.render(template, {msg: msg, type: type});
        $('#alert-template').remove();
        $( "#alerts" ).append(rendered);
    });
}

/** Clear local storage and refresh views. */
$( "#clear-views" ).click(function() {
    showLoading();
    localStorage.clear();
    refreshViews();
});

/** Refresh the current XSLT processors. */
function refreshXSLTProcessors() {
    var tableXSLT = $('#select-table-xslt').val();
    var listXSLT = $('#select-list-xslt').val();

    // Load the table XSLT
    var tablePromise = Promise.resolve($.ajax({
        url: "assets/xsl/" + tableXSLT
    })).then(function(result) {
        tableXSLTProcessor = new XSLTProcessor();
        tableXSLTProcessor.importStylesheet(result);

        //Then load the list XSLT
        var listPromise = Promise.resolve($.ajax({
            url: "assets/xsl/" + listXSLT
        })).then(function(result) {
            listXSLTProcessor = new XSLTProcessor();
            listXSLTProcessor.importStylesheet(result);
            refreshViews();
        }, function() {
            showAlert(listXSLT + ' could not be loaded', 'danger');
        });
    }, function() {
        showAlert(tableXSLT + ' could not be loaded', 'danger');
    });
}

/** Export the table to CSV. */
$( "#csv-export" ).click(function() {
    // Return an escaped CSV string
    function formatCSV(str) {
        return escapedStr = '"' + str.replace(/"/g, '""') + '"';
    }

    // Get table rows
    var rows = [];
    $('table tr').each(function() {
        var row = [];
        $(this).find('th,td').each(function () {
            var val = $(this)[0].innerHTML;
            row.push(val)
        });
        rows.push(row.join(','));
    });

    var csvString = rows.join("\n");
    console.log(csvString);
    var encodedUri = encodeURI('data:attachment/csv;charset=utf-8,' + csvString);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "tei_data.csv");
    link.click();
});

/** Load and return an XML document. */
function loadXMLDoc(text) {
    var parseXml;
    if (typeof window.DOMParser != "undefined") {
        parseXml = function(xmlStr) {
            return (new window.DOMParser()).parseFromString(xmlStr, "text/xml");
        };
    } else if (typeof window.ActiveXObject != "undefined" &&
        new window.ActiveXObject("Microsoft.XMLDOM")) {
        parseXml = function(xmlStr) {
            var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = "false";
            xmlDoc.loadXML(xmlStr);
            return xmlDoc;
        };
    } else {
        var msg = "No XML parser found";
        showAlert(msg, 'danger')
        throw new Error(msg);
    }
    return parseXml(text);
}

//Function to convert boolean to capitalized string
Boolean.prototype.toCapsString = function () {
    return this.toString().charAt(0).toUpperCase() + this.toString().slice(1);
}

/** Reset to default settings. */
$( "#default-settings" ).click(function() {
    loadDefaultSettings();
});

/** Handle change of load table XSLT setting. */
$( "#select-table-xslt" ).change(function() {
    showLoading();
    var settings = Cookies.getJSON('settings');
    settings.xsl.selectedTable = $('#select-table-xslt').val();
    Cookies.set('settings', settings);
    refreshXSLTProcessors();
});

/** Handle change of load list XSLT setting. */
$( "#select-list-xslt" ).change(function() {
    showLoading();
    var settings = Cookies.getJSON('settings');
    settings.xsl.selectedList = $('#select-list-xslt').val();
    Cookies.set('settings', settings);
    refreshXSLTProcessors();
});

/** Handle change of unique filenames setting. */
$( "#unique-fn" ).change(function() {
    var settings = Cookies.getJSON('settings');
    var uniqueFn = $('#unique-fn').val() == 'True';
    settings.uniqueFilenames = uniqueFn;
    Cookies.set('settings', settings);
    console.log(Cookies.get('settings'));
});

/** Load settings from cookie. */
function loadSettings(){
    var settings = Cookies.getJSON('settings');

    // XSLT files
    $.each( settings.xsl.table, function( key, val ) {
        var html = '<option value="' + val + '">' + key + '</option>';
        $('#select-table-xslt').append(html);
    });
    $.each( settings.xsl.list, function( key, val ) {
        var html = '<option value="' + val + '">' + key + '</option>';
        $('#select-list-xslt').append(html);
    });
    $('#select-table-xslt').val(settings.xsl.selectedTable);
    $('#select-list-xslt').val(settings.xsl.selectedList);

    // Unique filenames
    var uniqueFn = settings.uniqueFilenames.toCapsString()
    $('#unique-fn').val(uniqueFn);

    $('.selectpicker').selectpicker('refresh');
    refreshXSLTProcessors();
}

/** Reset to default settings. */
function loadDefaultSettings() {
    $.getJSON( "settings.json", function( settings ) {
        Cookies.set('settings', settings);
        loadSettings();
    }).then(function() {
        refreshXSLTProcessors();
    }, function() {
        showAlert('A valid settings file could not be found', 'danger')
    });
}

$(function() {
    showLoading();

    // Check for required HTML5 features
    if (typeof(localStorage) == 'undefined' ) {
        showAlert('Your browser does not support HTML5 localStorage. \
                  Try upgrading.', 'danger');
    }
    if (typeof(FileReader) == 'undefined' || typeof(File) == 'undefined'
        || typeof(FileList) == 'undefined' || typeof(Blob) == 'undefined') {
        showAlert('Your browser does not support the HTML5 File APIs. \
                  Try upgrading.', 'danger');
    }

    // Initialise settings from cookie or defaults
    if (typeof Cookies.get('settings') != "undefined") {
        loadSettings();
    } else {
        loadDefaultSettings();
    }
});
<|endoftext|>


<commit_before>import $ from 'jquery';

class BaseGeocoder {

    constructor(options) {

        // initialize options
        this.options = {};

        // Altering using user-provided options
        for (const property in options) {
            if (options.hasOwnProperty(property)) {
                this.options[property] = options[property];
            }
        }

        // initialize parser configurations
        this.parser_configurations = {

            'US': {
                regex: /^(\d+)?(\D+)((suite|ste|#)?\s*\d+)?$/i,
                street_components: ['number', 'street', 'unit']
            },

            'MX': {
                regex: /^(\D+)(\d+|s\/n)?(\D+\d*)?$/i,
                street_components: ['street', 'number', 'unit']
            }

        }

    }

    // parse street address
    parse_street_address(street_address, country, address) {

        // initialize address
        address = address || {};

        // parse street address
        const street = street_address.split(',');

        // load configuration based on country
        const config = this.parser_configurations[country];

        const matches = street[0].match(config['regex']);
        if (matches) {
            console.log(matches);
            const street_components = config['street_components'];
            // matches[0] is the entire matched string
            for (let i = 1; i < matches.length; i++) {
                if (matches[i] !== undefined)
                    address[street_components[i - 1]] = matches[i].trim();
            }
        }

        return address;
    }

    reverse(location, callback, options) {
        throw new Error("Not implemented!");
    }

    geocode(location, callback, options) {
        throw new Error("Not implemented!");
    }

}

export class GeocoderMapBox extends BaseGeocoder {

    constructor(options) {

        // add query default parameters
        options['types'] = 'address';
        options['limit'] = 1;

        // call super
        super(options);

    }

    parse_response(response) {

        // retrieve features
        const features = response.features;
        if (features.length == 0)
            return null;

        // parse first feature
        const feature = features[0];
        if (feature['place_type'] == 'address') {

            let address = {
                street_address: "",
                number: "",
                street: "",
                unit: undefined,
                neighborhood: undefined,
                city: "",
                state: "",
                zipcode: undefined,
                country: "",
                location: undefined
            };

            // set location
            address['location'] = {
                'latitude': feature['center'][1],
                'longitude': feature['center'][0]
            };

            // parse context
            const context = feature['context'];
            for (let i = 0; i < context.length; i++) {
                const item = context[i];
                const id = item['id'];
                if (id.startsWith('neighborhood'))
                    address['neighborhood'] = item['text'];
                else if (id.startsWith('postcode'))
                    address['zipcode'] = item['text'];
                else if (id.startsWith('place'))
                    address['city'] = item['text'];
                else if (id.startsWith('region'))
                    address['state'] = item['short_code'].toUpperCase().substr(3);
                else if (id.startsWith('country'))
                    address['country'] = item['short_code'].toUpperCase();
            }

            // set street_address
            const street_address = feature['place_name'];
            address['street_address'] = street_address;

            // parse street address
            return this.parse_street_address(street_address,
                address['country'],
                address);

        }

        // log error
        console.log("Does not know how to parse feature of type '" + feature['place_type'] + "'");

        return null;
    }

    reverse(location, callback, options) {

        options = options || {};

        let property;
        let url = "https://api.mapbox.com/geocoding/v5/mapbox.places/";

        const parameters = this.options;

        // Start with class options
        for (property in this.options) {
            if (this.options.hasOwnProperty(property)) {
                parameters[property] = this.options[property];
            }
        }

        // Altering using user-provided options
        for (property in options) {
            if (options.hasOwnProperty(property)) {
                parameters[property] = options[property];
            }
        }

        // construct query
        url += location.lng + ',' + location.lat + ".json";

        // add parameters
        let prefix = '?';
        for (const option in parameters) {
            if (parameters.hasOwnProperty(option)) {

                // add options
                url += prefix
                    + encodeURIComponent(option)
                    + "="
                    + encodeURIComponent(parameters[option]);
                prefix = '&';

            }
        }

        // query mapbox
        $.getJSON(url, function (response) {

            // parse results
            const address = GeocoderMapBox.this.parse_response(response);

            // callback
            if (callback)
                callback(address, response);

        })
            .fail(function (jqxhr, textStatus, error) {

                if (callback)
                    callback(null, {error: error});
                else
                    alert("Could not geocode:" +
                        textStatus + "," + error + "\n");

            });

    }

    geocode(query, callback, options) {

        options = options || { autocomplete: 'true' };

        let property;
        let url = "https://api.mapbox.com/geocoding/v5/mapbox.places/";

        const parameters = this.options;

        // Start with class options
        for (property in this.options) {
            if (this.options.hasOwnProperty(property)) {
                parameters[property] = this.options[property];
            }
        }

        // Altering using user-provided options
        for (property in options) {
            if (options.hasOwnProperty(property)) {
                parameters[property] = options[property];
            }
        }

        // construct query
        url += encodeURIComponent(query) + ".json";

        // add parameters
        let prefix = '?';
        for (const option in parameters) {
            if (parameters.hasOwnProperty(option)) {

                // add options
                url += prefix
                    + encodeURIComponent(option)
                    + "="
                    + encodeURIComponent(parameters[option]);
                prefix = '&';

            }
        }

        // query mapbox
        $.getJSON(url, function (response) {

            // parse results
            const address = GeocoderMapBox.this.parse_response(response);

            // callback
            if (callback)
                callback(address, response);

        })
            .fail(function (jqxhr, textStatus, error) {

                if (callback)
                    callback(null, {error: error});
                else
                    alert("Could not geocode:" +
                        textStatus + "," + error + "\n");

            });

    }

}

export class GeocoderGoogle extends BaseGeocoder {

}

/**
 * @return {null}
 */
export function GeocoderFactory(map_provider, options) {

    // default empty options
    options = options || {};

    // Retrieve MapBox access_token
    const provider = map_provider['provider'];
    if (provider === 'mapbox') {
        // add access token
        options['access_token'] = map_provider['access_token'];
        return new GeocoderMapBox(options);
    } else if (provider === 'google') {
        return new GeocoderGoogle(options);
    } else
        return null;

}

<commit_msg>Refactoring Geocoder to multiple providers.<commit_after>import $ from 'jquery';

class BaseGeocoder {

    constructor(options) {

        // initialize options
        this.options = {};

        // Altering using user-provided options
        for (const property in options) {
            if (options.hasOwnProperty(property)) {
                this.options[property] = options[property];
            }
        }

        // initialize parser configurations
        this.parser_configurations = {

            'US': {
                regex: /^(\d+)?(\D+)((suite|ste|#)?\s*\d+)?$/i,
                street_components: ['number', 'street', 'unit']
            },

            'MX': {
                regex: /^(\D+)(\d+|s\/n)?(\D+\d*)?$/i,
                street_components: ['street', 'number', 'unit']
            }

        }

    }

    // parse street address
    parse_street_address(street_address, country, address) {

        // initialize address
        address = address || {};

        // parse street address
        const street = street_address.split(',');

        // load configuration based on country
        const config = this.parser_configurations[country];

        const matches = street[0].match(config['regex']);
        if (matches) {
            console.log(matches);
            const street_components = config['street_components'];
            // matches[0] is the entire matched string
            for (let i = 1; i < matches.length; i++) {
                if (matches[i] !== undefined)
                    address[street_components[i - 1]] = matches[i].trim();
            }
        }

        return address;
    }

    reverse(location, callback, options) {
        throw new Error("Not implemented!");
    }

    geocode(location, callback, options) {
        throw new Error("Not implemented!");
    }

}

export class GeocoderMapBox extends BaseGeocoder {

    constructor(options) {

        // add query default parameters
        options['types'] = 'address';
        options['limit'] = 1;

        // call super
        super(options);

    }

    parse_response(response) {

        // retrieve features
        const features = response.features;
        if (features.length == 0)
            return null;

        // parse first feature
        const feature = features[0];
        if (feature['place_type'] == 'address') {

            let address = {
                street_address: "",
                number: "",
                street: "",
                unit: undefined,
                neighborhood: undefined,
                city: "",
                state: "",
                zipcode: undefined,
                country: "",
                location: undefined
            };

            // set location
            address['location'] = {
                'latitude': feature['center'][1],
                'longitude': feature['center'][0]
            };

            // parse context
            const context = feature['context'];
            for (let i = 0; i < context.length; i++) {
                const item = context[i];
                const id = item['id'];
                if (id.startsWith('neighborhood'))
                    address['neighborhood'] = item['text'];
                else if (id.startsWith('postcode'))
                    address['zipcode'] = item['text'];
                else if (id.startsWith('place'))
                    address['city'] = item['text'];
                else if (id.startsWith('region'))
                    address['state'] = item['short_code'].toUpperCase().substr(3);
                else if (id.startsWith('country'))
                    address['country'] = item['short_code'].toUpperCase();
            }

            // set street_address
            const street_address = feature['place_name'];
            address['street_address'] = street_address;

            // parse street address
            return this.parse_street_address(street_address,
                address['country'],
                address);

        }

        // log error
        console.log("Does not know how to parse feature of type '" + feature['place_type'] + "'");

        return null;
    }

    reverse(location, callback, options) {

        options = options || {};

        let property;
        let url = "https://api.mapbox.com/geocoding/v5/mapbox.places/";

        const parameters = this.options;

        // Start with class options
        for (property in this.options) {
            if (this.options.hasOwnProperty(property)) {
                parameters[property] = this.options[property];
            }
        }

        // Altering using user-provided options
        for (property in options) {
            if (options.hasOwnProperty(property)) {
                parameters[property] = options[property];
            }
        }

        // construct query
        url += location.lng + ',' + location.lat + ".json";

        // add parameters
        let prefix = '?';
        for (const option in parameters) {
            if (parameters.hasOwnProperty(option)) {

                // add options
                url += prefix
                    + encodeURIComponent(option)
                    + "="
                    + encodeURIComponent(parameters[option]);
                prefix = '&';

            }
        }

        // query mapbox
        $.getJSON(url, function (response) {

            // parse results
            const address = this.parse_response(response);

            // callback
            if (callback)
                callback(address, response);

        }.bind(this))
            .fail(function (jqxhr, textStatus, error) {

                if (callback)
                    callback(null, {error: error});
                else
                    alert("Could not geocode:" +
                        textStatus + "," + error + "\n");

            });

    }

    geocode(query, callback, options) {

        options = options || { autocomplete: 'true' };

        let property;
        let url = "https://api.mapbox.com/geocoding/v5/mapbox.places/";

        const parameters = this.options;

        // Start with class options
        for (property in this.options) {
            if (this.options.hasOwnProperty(property)) {
                parameters[property] = this.options[property];
            }
        }

        // Altering using user-provided options
        for (property in options) {
            if (options.hasOwnProperty(property)) {
                parameters[property] = options[property];
            }
        }

        // construct query
        url += encodeURIComponent(query) + ".json";

        // add parameters
        let prefix = '?';
        for (const option in parameters) {
            if (parameters.hasOwnProperty(option)) {

                // add options
                url += prefix
                    + encodeURIComponent(option)
                    + "="
                    + encodeURIComponent(parameters[option]);
                prefix = '&';

            }
        }

        // query mapbox
        $.getJSON(url, function (response) {

            // parse results
            const address = this.parse_response(response);

            // callback
            if (callback)
                callback(address, response);

        }.bind(this))
            .fail(function (jqxhr, textStatus, error) {

                if (callback)
                    callback(null, {error: error});
                else
                    alert("Could not geocode:" +
                        textStatus + "," + error + "\n");

            });

    }

}

export class GeocoderGoogle extends BaseGeocoder {

}

/**
 * @return {null}
 */
export function GeocoderFactory(map_provider, options) {

    // default empty options
    options = options || {};

    // Retrieve MapBox access_token
    const provider = map_provider['provider'];
    if (provider === 'mapbox') {
        // add access token
        options['access_token'] = map_provider['access_token'];
        return new GeocoderMapBox(options);
    } else if (provider === 'google') {
        return new GeocoderGoogle(options);
    } else
        return null;

}

<|endoftext|>


<commit_before>const flightController = require('../controllers/flights.js');
const anywhereController = require('../controllers/anywhere.js');
const geocoderController = require('../controllers/geocoder.js');
const hotelController = require('../controllers/hotels.js');
const weatherController = require('../controllers/weather.js');
const databaseController = require('../controllers/database.js');
const yelp = require('../controllers/yelp.js');
const viator = require('../controllers/viator.js');
const frommers = require('../controllers/frommers.js');
const googlePlacesController = require('../controllers/googlePlacesFlights');

module.exports = (app, express) => {
  app.get('/api/flights', flightController.getFlights);
  app.get('/api/geocoder', geocoderController.location);
  app.get('/api/weather', weatherController.getWeather);
  app.get('/api/yelp', yelp.getEvents);
  app.get('/api/dbQuery', databaseController.getProfile);
  app.get('/api/viator', viator.scrape);
  app.get('/api/frommers', frommers.scrape);

  // Activate for testing
  // app.get('/api/anywhere', anywhereController.getAnywhereDummy);
  // app.get('/api/hotels', hotelController.getHotelsDummy);

  // //Live
  app.get('/api/anywhere', anywhereController.getAnywhere);
  app.get('/api/hotels', hotelController.getHotels);

  app.get('/api/google', googlePlacesController.getGoogleData);

  // Analysis
  app.get('/api/dbSearchQuerySave', databaseController.saveQuery);
};
<commit_msg>uncommented dummy data<commit_after>const flightController = require('../controllers/flights.js');
const anywhereController = require('../controllers/anywhere.js');
const geocoderController = require('../controllers/geocoder.js');
const hotelController = require('../controllers/hotels.js');
const weatherController = require('../controllers/weather.js');
const databaseController = require('../controllers/database.js');
const yelp = require('../controllers/yelp.js');
const viator = require('../controllers/viator.js');
const frommers = require('../controllers/frommers.js');
const googlePlacesController = require('../controllers/googlePlacesFlights');

module.exports = (app, express) => {
  app.get('/api/flights', flightController.getFlights);
  app.get('/api/geocoder', geocoderController.location);
  app.get('/api/weather', weatherController.getWeather);
  app.get('/api/yelp', yelp.getEvents);
  app.get('/api/dbQuery', databaseController.getProfile);
  app.get('/api/viator', viator.scrape);
  app.get('/api/frommers', frommers.scrape);

  // Activate for testing
  app.get('/api/anywhere', anywhereController.getAnywhereDummy);
  app.get('/api/hotels', hotelController.getHotelsDummy);

  // //Live
  // app.get('/api/anywhere', anywhereController.getAnywhere);
  // app.get('/api/hotels', hotelController.getHotels);

  app.get('/api/google', googlePlacesController.getGoogleData);

  // Analysis
  app.get('/api/dbSearchQuerySave', databaseController.saveQuery);
};
<|endoftext|>


<commit_before>import $ from 'jquery';
import 'foundation/js/foundation/foundation';
import 'foundation/js/foundation/foundation.dropdown';
import utils from 'bigcommerce/stencil-utils';

export default function () {
    let loadingClass = 'is-loading',
        $cart = $('[data-cart-preview]'),
        $cartDropdown = $('#cart-preview-dropdown'),
        $cartLoading = $('

');

    $('body').on('cart-quantity-update', function(event, quantity) {
        let $cartQty = $('.cart-quantity');

        $cartQty.text(quantity);

        if (quantity > 0) {
            $cartQty.addClass('countPill--positive');
        } else {
            $cartQty.removeClass('countPill--positive');
        }
    });

    $cart.on('click', (event) => {
        let options = {
            template: 'common/cart-preview'
        };

        $cartDropdown
            .addClass(loadingClass)
            .html($cartLoading);

        event.preventDefault();

        utils.api.cart.getContent(options, (err, response) => {
            let quantity;

            $cartDropdown
                .removeClass(loadingClass)
                .html(response);

            quantity = $('[data-cart-quantity]', $cartDropdown).data('cart-quantity') || 0;
            $('body').trigger('cart-quantity-update', quantity);
        });
    });
}
<commit_msg>using toggleClass<commit_after>import $ from 'jquery';
import 'foundation/js/foundation/foundation';
import 'foundation/js/foundation/foundation.dropdown';
import utils from 'bigcommerce/stencil-utils';

export default function () {
    let loadingClass = 'is-loading',
        $cart = $('[data-cart-preview]'),
        $cartDropdown = $('#cart-preview-dropdown'),
        $cartLoading = $('

');

    $('body').on('cart-quantity-update', function(event, quantity) {
        $('.cart-quantity')
            .text(quantity)
            .toggleClass('countPill--positive', quantity > 0);
    });

    $cart.on('click', (event) => {
        let options = {
            template: 'common/cart-preview'
        };

        $cartDropdown
            .addClass(loadingClass)
            .html($cartLoading);

        event.preventDefault();

        utils.api.cart.getContent(options, (err, response) => {
            let quantity;

            $cartDropdown
                .removeClass(loadingClass)
                .html(response);

            quantity = $('[data-cart-quantity]', $cartDropdown).data('cart-quantity') || 0;
            $('body').trigger('cart-quantity-update', quantity);
        });
    });
}
<|endoftext|>