<commit_before>/* Nitro Core
 *
 * Copyright (C) 2012 Caffeinated Code <http://caffeinatedco.de>
 * Copyright (C) 2012 Jono Cooper
 * Copyright (C) 2012 George Czabania
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of Caffeinated Code nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

app = 'js'
version = '1.5'

//Core Module
var core = {
	getID: function() {
		var bit = function() {
			return (Math.floor(Math.random() *36)).toString(36)
		},
		part = function() {
			return bit() + bit() + bit() + bit()
		}
		return part() + "-" + part() + "-" + part()
	},
	task: function(id) {
		return {
			add: function(name, list) {
				//ID of task
				var taskID = core.getID()

				//Saves
				core.storage.tasks[taskID] = {
					content: name,
					priority: 'none',
					date: '',
					notes: '',
					list: list,
					logged: false,
					tags: [],
					time: {
						content: 0,
						priority: 0,
						date: 0,
						notes: 0,
						list: 0,
						logged: 0,
						tags: 0
					}
				};

				//Pushes to array
				core.storage.lists.items[list].order.unshift(taskID);
				core.storage.save([['lists', list, 'order']]);
				console.log('Adding Task: ' + name + ' into list: ' + list);

				return taskID;
			},

			/* Move a task somewhere.
			e.g: core.task(0).move('next');

			To delete something, move to 'trash' */

			move: function(list) {
				//Fix for scheduled list
				if (core.storage.tasks[id].type) {
					var old = 'scheduled';
				} else {
					var old = core.storage.tasks[id].list;
				}

				// Dropping a task onto the Logbook completes it
				if(list == 'logbook' && !core.storage.tasks[id].logged) {
					core.storage.tasks[id].logged = core.timestamp();
					console.log('Logged ' + id);
					core.storage.save([['tasks', id, 'logged']]);
				}

				// Taking a task out of the logbook
				if(core.storage.tasks[id].list == list && core.storage.tasks[id].logged && list != 'logbook') {
					console.log("Unlogging task")
					core.storage.tasks[id].logged = false;
					core.storage.save([['tasks', id, 'logged']]);
				} else if (list === 'trash') {
					//Remove from list
					if(core.storage.lists.items.hasOwnProperty(old)) {
						if(!core.storage.lists.items[old].hasOwnProperty('deleted')) {

							var index = core.storage.lists.items[old].order.indexOf(id)
							if(index > -1) core.storage.lists.items[old].order.splice(index, 1)
							console.log(old, core.storage.lists.items[old].order, id, index)
							core.storage.save([['lists', old, 'order']])
						}
					}
					// delete core.storage.tasks[id];
					core.storage.tasks[id] = {deleted: core.timestamp()};
					console.log('Deleted: ' + id);
					// Saves
					core.storage.save();
				} else {
					//Remove from list
					if(core.storage.lists.items.hasOwnProperty(old)) {
						if(!core.storage.lists.items[old].hasOwnProperty('deleted')) {

							var index = core.storage.lists.items[old].order.indexOf(id)
							if(index > -1) core.storage.lists.items[old].order.splice(index, 1)
							console.log(old, core.storage.lists.items[old].order, id, index)
							core.storage.save([['lists', old, 'order']])
						}
					}
					//Move to other list
					core.storage.lists.items[list].order.unshift(id);
					core.storage.tasks[id].list = list;
					console.log('Moved: ' + id + ' to ' + list);
					//Saves
					core.storage.save([['tasks', id, 'list'],['lists', list, 'order']]);
				}
			},
			toggle: function() {
				var task = core.storage.tasks[id]
				if(task.logged) {
					task.logged = false
				} else {
					task.logged = core.timestamp()
				}
				core.storage.save([['tasks', id, 'logged']])
			}
		}
	},

	list: function(id) {
		return {
			add: function(name) {
				//New ID
				var listID = core.getID()

				//Chucks data in object
				core.storage.lists.items[listID] = {
					name: name,
					order: [],
					time: {
						name: 0,
						order: 0
					}
				}

				//Adds to order array
				core.storage.lists.order.push(listID)
				core.storage.save([['list-order', null, null]])
				console.log("Created List: '" + name + "' with id: " + listID)

				return listID
			},
			delete: function() {
				//Deletes tasks in a list
				for (var i = core.storage.lists.items[id].order.length - 1; i >= 0; i--) {
					core.task(core.storage.lists.items[id].order[i]).move('trash')
				}

				//Remove from List order
				var index = core.storage.lists.order.indexOf(id)
				if(index > -1) core.storage.lists.order.splice(index, 1)

				//Deletes List
				core.storage.lists.items[id] = {deleted: core.timestamp()}
				core.storage.save([['list-order', null, null]])
			},
			populate: function() {
				switch(id) {

					case 'today':

						// Get current tasks in today list and also get tasks that are due today
						var current = core.storage.lists.items.today.order,
							today = filter(core.list('all').populate(), {date: ['overdue', 'today']}),
							smartTasks = []

						// Loop through each task currently in today and check to see if it is actually
						// in the today list or if it was added there by this function
						for(var i = 0; i < current.length; i++) {
							if(core.storage.tasks[current[i]].list !== 'today') {
								smartTasks.push(current[i])
							}
						}

						// Make sure the task is still in today
						var remove = smartTasks.filter(function(i) {return !(today.indexOf(i) > -1)})

						// Remove each task that was in today but not anymore
						for(var i = 0; i < remove.length; i++) {
							current.splice(current.indexOf(remove[i]), 1)
						}

						// Add in any new tasks
						var add = today.filter(function(i) {return !(current.indexOf(i) > -1);})
						current = current.concat(add)

						return plugin.sort(current, core.storage.prefs.listSort['today'])

					case 'all':

						var results = [];

						// Loop
						for (var i in core.storage.tasks) {
							if(!core.storage.tasks[i].hasOwnProperty('deleted') && !core.storage.tasks[i].logged) {
								results.push(i)
							}
						}

						return plugin.sort(results, core.storage.prefs.listSort['all'])

					default:
						if (core.storage.lists.items.hasOwnProperty(id)) {
							var order = core.storage.lists.items[id].order
							if(!core.storage.prefs.listSort.hasOwnProperty(id)) {
								core.storage.prefs.listSort[id] = 'magic'
							}
							return plugin.sort(order, core.storage.prefs.listSort[id])
							//return order
						} else {
							return [];
						}
				}
			}
		}
	},

	date:  function(timestamp) {
		var months = [
			$.i18n._('janShort'),
			$.i18n._('febShort'),
			$.i18n._('marShort'),
			$.i18n._('aprShort'),
			$.i18n._('mayShort'),
			$.i18n._('junShort'),
			$.i18n._('julShort'),
			$.i18n._('augShort'),
			$.i18n._('sepShort'),
			$.i18n._('octShort'),
			$.i18n._('novShort'),
			$.i18n._('decShort')
		];
		return {
			getDaysLeft: function() {
				if(!timestamp) return false

				// Create Date()
				var date = new Date(timestamp),
					now = new Date(),
					difference = 0,
					oneDay = 86400000; // 1000*60*60*24 - one day in milliseconds

				// Find difference between days
				difference = Math.ceil((date.getTime() - now.getTime()) / oneDay)

				var words, className = ''

				/*

					Difference

					==  5: "5 days left"
					==  1: "Due tomorrow"
					==  0: "Due today"
					== -1: "Due yesterday"
					== -5: "5 days overdue"

				*/

				// Show difference nicely
				if (difference === -1) {
					// Yesterday
					words = $.i18n._('dueYesterday')
					className = 'overdue'

				} else if (difference < -1) {
					// Overdue

					// Make sure the difference is a positive number
					difference = Math.abs(difference);
					words = $.i18n._('daysOverdue', [difference])
					className = 'overdue'

				} else if (difference === 0) {
					// Due Today
					words = $.i18n._('dueToday')
					className = 'due'

				} else if (difference === 1) {
					// Due Tomorrow
					words = $.i18n._('dueTomorrow')
					className = 'soon'

				} else if (difference < 15) {
					// Due in the next 15 days
					words = $.i18n._('daysLeft', [difference])

				} else {
					// Due after 15 days
					words = months[date.getMonth()] + " " + date.getDate()
				}

				return {
					words: words,
					className: className
				}
			},

			getDate: function() {

			if(!timestamp) return false;

				var date = new Date(timestamp),
					now = new Date(),
					d = 0,
					oneDay = 86400000;

				// Find difference between days
				d = Math.ceil((date.getTime() - now.getTime()) / oneDay);

				if(d == 0) {
					return "Today"
				} else if (d == -1) {
					return "Yesterday"
				} else {
					return date.getDate() + " " + months[date.getMonth()];
				}
			}
		}
	},

	storage: {
		tasks: $.polyStorage.get('tasks', {}),
		lists: $.polyStorage.get('lists', {
			order: [],
			items: {
				today: {
					order: [],
					time: {
						order: 0
					}
				},
				next: {
					order: [],
					time: {
						order: 0
					}
				},
				logbook: {
					order: [],
					time: {
						order: 0
					}
				}
			},
			time: 0
		}),
		prefs: $.polyStorage.get('prefs', {
			listSort: {},
			sync: {
				url: "http://app.nitrotasks.com",
				interval: 'manual'
			},
			version: version
		}),
		save: function(arr) {

			if(typeof arr == 'object') {
				for(var i = 0; i < arr.length; i++) {
					var type = arr[i][0],
						id = arr[i][1],
						key = arr[i][2];
					switch(type) {
						case 'tasks':
							console.log('Updating timestamp for '+ key +' in task '+ id);
							core.storage.tasks[id].time[key] = core.timestamp();
							break;
						case 'lists':
							console.log('Updating timestamp for '+ key +' in list '+ id);
							core.storage.lists.items[id].time[key] = core.timestamp();
							break;
						case 'list-order':
							console.log('Updating timestamp for List order');
							core.storage.lists.time = core.timestamp();
							break;
					}
				}
			} else if(arr !== undefined) console.log("Error: timestamp could not be updated - data needs to be in an array")

			$.polyStorage.set('tasks', this.tasks);
			$.polyStorage.set('lists', this.lists);
			$.polyStorage.set('prefs', this.prefs);
		}
	},
	timestamp: function() {
		return Date.now();
	}
}<commit_msg>Added core.storage.store()<commit_after>/* Nitro Core
 *
 * Copyright (C) 2012 Caffeinated Code <http://caffeinatedco.de>
 * Copyright (C) 2012 Jono Cooper
 * Copyright (C) 2012 George Czabania
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of Caffeinated Code nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

app = 'js'
version = '1.5'

//Core Module
var core = {
	getID: function() {
		var bit = function() {
			return (Math.floor(Math.random() *36)).toString(36)
		},
		part = function() {
			return bit() + bit() + bit() + bit()
		}
		return part() + "-" + part() + "-" + part()
	},
	task: function(id) {
		return {
			add: function(name, list) {
				//ID of task
				var taskID = core.getID()

				//Saves
				core.storage.tasks[taskID] = {
					content: name,
					priority: 'none',
					date: '',
					notes: '',
					list: list,
					logged: false,
					tags: [],
					time: {
						content: 0,
						priority: 0,
						date: 0,
						notes: 0,
						list: 0,
						logged: 0,
						tags: 0
					}
				};

				//Pushes to array
				core.storage.lists.items[list].order.unshift(taskID);
				core.storage.save([['lists', list, 'order']]);
				console.log('Adding Task: ' + name + ' into list: ' + list);

				return taskID;
			},

			/* Move a task somewhere.
			e.g: core.task(0).move('next');

			To delete something, move to 'trash' */

			move: function(list) {
				//Fix for scheduled list
				if (core.storage.tasks[id].type) {
					var old = 'scheduled';
				} else {
					var old = core.storage.tasks[id].list;
				}

				// Dropping a task onto the Logbook completes it
				if(list == 'logbook' && !core.storage.tasks[id].logged) {
					core.storage.tasks[id].logged = core.timestamp();
					console.log('Logged ' + id);
					core.storage.save([['tasks', id, 'logged']]);
				}

				// Taking a task out of the logbook
				if(core.storage.tasks[id].list == list && core.storage.tasks[id].logged && list != 'logbook') {
					console.log("Unlogging task")
					core.storage.tasks[id].logged = false;
					core.storage.save([['tasks', id, 'logged']]);
				} else if (list === 'trash') {
					//Remove from list
					if(core.storage.lists.items.hasOwnProperty(old)) {
						if(!core.storage.lists.items[old].hasOwnProperty('deleted')) {

							var index = core.storage.lists.items[old].order.indexOf(id)
							if(index > -1) core.storage.lists.items[old].order.splice(index, 1)
							console.log(old, core.storage.lists.items[old].order, id, index)
							core.storage.save([['lists', old, 'order']])
						}
					}
					// delete core.storage.tasks[id];
					core.storage.tasks[id] = {deleted: core.timestamp()};
					console.log('Deleted: ' + id);
					// Saves
					core.storage.save();
				} else {
					//Remove from list
					if(core.storage.lists.items.hasOwnProperty(old)) {
						if(!core.storage.lists.items[old].hasOwnProperty('deleted')) {

							var index = core.storage.lists.items[old].order.indexOf(id)
							if(index > -1) core.storage.lists.items[old].order.splice(index, 1)
							console.log(old, core.storage.lists.items[old].order, id, index)
							core.storage.save([['lists', old, 'order']])
						}
					}
					//Move to other list
					core.storage.lists.items[list].order.unshift(id);
					core.storage.tasks[id].list = list;
					console.log('Moved: ' + id + ' to ' + list);
					//Saves
					core.storage.save([['tasks', id, 'list'],['lists', list, 'order']]);
				}
			},
			toggle: function() {
				var task = core.storage.tasks[id]
				if(task.logged) {
					task.logged = false
				} else {
					task.logged = core.timestamp()
				}
				core.storage.save([['tasks', id, 'logged']])
			}
		}
	},

	list: function(id) {
		return {
			add: function(name) {
				//New ID
				var listID = core.getID()

				//Chucks data in object
				core.storage.lists.items[listID] = {
					name: name,
					order: [],
					time: {
						name: 0,
						order: 0
					}
				}

				//Adds to order array
				core.storage.lists.order.push(listID)
				core.storage.save([['list-order', null, null]])
				console.log("Created List: '" + name + "' with id: " + listID)

				return listID
			},
			delete: function() {
				//Deletes tasks in a list
				for (var i = core.storage.lists.items[id].order.length - 1; i >= 0; i--) {
					core.task(core.storage.lists.items[id].order[i]).move('trash')
				}

				//Remove from List order
				var index = core.storage.lists.order.indexOf(id)
				if(index > -1) core.storage.lists.order.splice(index, 1)

				//Deletes List
				core.storage.lists.items[id] = {deleted: core.timestamp()}
				core.storage.save([['list-order', null, null]])
			},
			populate: function() {
				switch(id) {

					case 'today':

						// Get current tasks in today list and also get tasks that are due today
						var current = core.storage.lists.items.today.order,
							today = filter(core.list('all').populate(), {date: ['overdue', 'today']}),
							smartTasks = []

						// Loop through each task currently in today and check to see if it is actually
						// in the today list or if it was added there by this function
						for(var i = 0; i < current.length; i++) {
							if(core.storage.tasks[current[i]].list !== 'today') {
								smartTasks.push(current[i])
							}
						}

						// Make sure the task is still in today
						var remove = smartTasks.filter(function(i) {return !(today.indexOf(i) > -1)})

						// Remove each task that was in today but not anymore
						for(var i = 0; i < remove.length; i++) {
							current.splice(current.indexOf(remove[i]), 1)
						}

						// Add in any new tasks
						var add = today.filter(function(i) {return !(current.indexOf(i) > -1);})
						current = current.concat(add)

						return plugin.sort(current, core.storage.prefs.listSort['today'])

					case 'all':

						var results = [];

						// Loop
						for (var i in core.storage.tasks) {
							if(!core.storage.tasks[i].hasOwnProperty('deleted') && !core.storage.tasks[i].logged) {
								results.push(i)
							}
						}

						return plugin.sort(results, core.storage.prefs.listSort['all'])

					default:
						if (core.storage.lists.items.hasOwnProperty(id)) {
							var order = core.storage.lists.items[id].order
							if(!core.storage.prefs.listSort.hasOwnProperty(id)) {
								core.storage.prefs.listSort[id] = 'magic'
							}
							return plugin.sort(order, core.storage.prefs.listSort[id])
							//return order
						} else {
							return [];
						}
				}
			}
		}
	},

	date:  function(timestamp) {
		var months = [
			$.i18n._('janShort'),
			$.i18n._('febShort'),
			$.i18n._('marShort'),
			$.i18n._('aprShort'),
			$.i18n._('mayShort'),
			$.i18n._('junShort'),
			$.i18n._('julShort'),
			$.i18n._('augShort'),
			$.i18n._('sepShort'),
			$.i18n._('octShort'),
			$.i18n._('novShort'),
			$.i18n._('decShort')
		];
		return {
			getDaysLeft: function() {
				if(!timestamp) return false

				// Create Date()
				var date = new Date(timestamp),
					now = new Date(),
					difference = 0,
					oneDay = 86400000; // 1000*60*60*24 - one day in milliseconds

				// Find difference between days
				difference = Math.ceil((date.getTime() - now.getTime()) / oneDay)

				var words, className = ''

				/*

					Difference

					==  5: "5 days left"
					==  1: "Due tomorrow"
					==  0: "Due today"
					== -1: "Due yesterday"
					== -5: "5 days overdue"

				*/

				// Show difference nicely
				if (difference === -1) {
					// Yesterday
					words = $.i18n._('dueYesterday')
					className = 'overdue'

				} else if (difference < -1) {
					// Overdue

					// Make sure the difference is a positive number
					difference = Math.abs(difference);
					words = $.i18n._('daysOverdue', [difference])
					className = 'overdue'

				} else if (difference === 0) {
					// Due Today
					words = $.i18n._('dueToday')
					className = 'due'

				} else if (difference === 1) {
					// Due Tomorrow
					words = $.i18n._('dueTomorrow')
					className = 'soon'

				} else if (difference < 15) {
					// Due in the next 15 days
					words = $.i18n._('daysLeft', [difference])

				} else {
					// Due after 15 days
					words = months[date.getMonth()] + " " + date.getDate()
				}

				return {
					words: words,
					className: className
				}
			},

			getDate: function() {

			if(!timestamp) return false;

				var date = new Date(timestamp),
					now = new Date(),
					d = 0,
					oneDay = 86400000;

				// Find difference between days
				d = Math.ceil((date.getTime() - now.getTime()) / oneDay);

				if(d == 0) {
					return "Today"
				} else if (d == -1) {
					return "Yesterday"
				} else {
					return date.getDate() + " " + months[date.getMonth()];
				}
			}
		}
	},

	storage: {
		tasks: $.polyStorage.get('tasks', {}),
		lists: $.polyStorage.get('lists', {
			order: [],
			items: {
				today: {
					order: [],
					time: {
						order: 0
					}
				},
				next: {
					order: [],
					time: {
						order: 0
					}
				},
				logbook: {
					order: [],
					time: {
						order: 0
					}
				}
			},
			time: 0
		}),
		prefs: $.polyStorage.get('prefs', {
			listSort: {},
			sync: {
				url: "http://app.nitrotasks.com",
				interval: 'manual'
			},
			version: version
		}),
		save: function(arr) {

			if(typeof arr == 'object') {
				for(var i = 0; i < arr.length; i++) {
					var type = arr[i][0],
						id = arr[i][1],
						key = arr[i][2];
					switch(type) {
						case 'tasks':
							console.log('Updating timestamp for '+ key +' in task '+ id);
							core.storage.tasks[id].time[key] = core.timestamp();
							break;
						case 'lists':
							console.log('Updating timestamp for '+ key +' in list '+ id);
							core.storage.lists.items[id].time[key] = core.timestamp();
							break;
						case 'list-order':
							console.log('Updating timestamp for List order');
							core.storage.lists.time = core.timestamp();
							break;
					}
				}
			} else if(arr !== undefined) console.log("Error: timestamp could not be updated - data needs to be in an array")

			// Save to database
			core.storage.store()

		},
		store: function() {
			$.polyStorage.set('tasks', core.storage.tasks);
			$.polyStorage.set('lists', core.storage.lists);
			$.polyStorage.set('prefs', core.storage.prefs);
		}
	},
	timestamp: function() {
		return Date.now();
	}
}<|endoftext|>


<commit_before>const auth = require('./auth');
const db = require('./db');

/**
 * Strips a DocumentDB object of its metadata fields so as not to expose them to the end user client.
 * @param {object} dbObj            A DocumentDB document object.
 * @returns {object}                Returns the DocumentDB object without its metadata properties.
 */
const strip = dbObj => {
  delete dbObj._rid;
  delete dbObj._attachments;
  delete dbObj._etag;
  delete dbObj._self;
  delete dbObj._ts;
  return dbObj;
};

// deletes items from a collection
exports.deleteFromCollection = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Deleting items from collection.' });
  }
};

/**
 * DELETE /{collection}/{item}
 * Deletes an item from a collection
 */
exports.deleteItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    if (res.locals.user.isOwner(req.params.itemId)) {
      db.deleteByIds(req.params.collection, [req.params.itemId])
      .then(() => r.res(null, 204, res))
      .catch(err => r.res(err, null, res));
    } else {
      r.res('User does not have sufficient permissions for this resource.', 403, res);
    }
  }
};

// deletes a lexicon entry
exports.deleteLexEntry = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Deleting lexicon entry.' });
  }
};

/**
 * GET /bundles/{bundleId}/items/{itemId}
 * Retrieves an item from a bundle
 */
exports.getBundleItem = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting item from bundle.' });
    },

    'application/json': () => {}

  });
};

/**
 * GET /{collection}
 * Retrieves items from a collection
 */
exports.getFromCollection = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting items from collection.' });
    },

    'application/json': () => {}

  });
};

/**
 * GET /{collection}/{itemId}
 * Retrieves a single item from a collection
 */
exports.getItem = (req, res) => {

  const errorHandler = err => {
    const errObj = r.convert(err);
    res.format({
      'text/html': () => res.render('error', errObj),
      'application/json': () => r.res(errObj, null, res)
    });
  };

  const successHandler = result => {
    if (result.permissions.public || (res.locals.user && res.locals.user.isViewer(result))) {
      res.format({
        'text/html': () => res.render('test', { test: JSON.stringify(strip(result), null, 2) }),
        'application/json': () => r.res(strip(result), 200, res)
      });
    } else {
      const errObj = r.json(res.locals.user ? 'User has insufficient permissions to access this resource.' : 'This is a private resource. Try logging in.', 403);
      res.format({
        'text/html': () => res.render('error', errObj),
        'application/json': () => r.res(errObj, null, res)
      });
    }
  };

  db.getById(req.params.collection, req.params.itemId)
  .then(successHandler)
  .catch(errorHandler);

};

/**
 * GET /lexicons/{lexiconId}/entries/{entryId}
 * Retrieves a lexicon entry from a lexicon
 */
exports.getLexEntry = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting lexicon entry.' });
    },

    'application/json': () => {}

  });
};

/**
 * GET /texts/{textId}/phrases/{phraseId}
 * Retrieves a phrase from a text
 */
exports.getPhrase = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting phrase.' });
    },

    'application/json': () => {}

  });
};

// removes an item from a bundle
exports.removeBundleItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Deleting item from bundle.' });
  }
};

// updates permissions or associated resources for a bundle item
exports.updateBundleItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Updating bundle item.' });
  }
};

// updates permissions or associated resources for multiple items
exports.updateCollectionItems = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Updating collection items.' });
  }
};

// upserts an item to a bundle (and saves it to the appropriate collection)
exports.upsertBundleItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Adding item to bundle.' });
  }
};

// updates permissions or associated resources for an item
exports.updateItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Updating item.' });
  }
};

// upserts an item to a collection
exports.upsertItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Upserting item.' });
  }
};

exports.upsertLexEntry = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Upserting lexicon entry.' });
  }
};

/**
 * POST /{collection}
 * Upserts items to a collection
 */
exports.upsertToCollection = (req, res) => {
  if (auth.checkToken(req, res)) {

    var isArr;
    const user = res.locals.user;

    const updateUser = results => new Promise((resolve, reject) => {
      isArr = results instanceof Array;
      if (isArr) { results.forEach(item => user.makeOwner(item)); }
      else { user.makeOwner(results); }
      db.upsert('users', user).then(() => resolve(results)).catch(reject);
    });

    db.upsert(req.params.collection, req.body)
    .then(updateUser)
    .then(results => {
      if (isArr) { r.res(results.map(strip), 201, res); }
      else { r.res(strip(results), 201, res); }
    })
    .catch(err => r.res(err, null, res));

  }
};
<commit_msg>update commenting on api.js<commit_after>const auth = require('./auth');
const db = require('./db');

/**
 * Strips a DocumentDB object of its metadata fields so as not to expose them to the end user client.
 * @param {object} dbObj            A DocumentDB document object.
 * @returns {object}                Returns the DocumentDB object without its metadata properties.
 */
const strip = dbObj => {
  delete dbObj._rid;
  delete dbObj._attachments;
  delete dbObj._etag;
  delete dbObj._self;
  delete dbObj._ts;
  return dbObj;
};

/**
 * DELETE /{collection}
 * Deletes items from a collection.
 */
exports.deleteFromCollection = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Deleting items from collection.' });
  }
};

/**
 * DELETE /{collection}/{item}
 * Deletes an item from a collection
 */
exports.deleteItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    if (res.locals.user.isOwner(req.params.itemId)) {
      db.deleteByIds(req.params.collection, [req.params.itemId])
      .then(() => r.res(null, 204, res))
      .catch(err => r.res(err, null, res));
    } else {
      r.res('User does not have sufficient permissions for this resource.', 403, res);
    }
  }
};

/**
 * DELETE /lexicons/{lexiconId}/entries/{entryId}
 * Deletes a lexicon entry.
 */
exports.deleteLexEntry = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Deleting lexicon entry.' });
  }
};

/**
 * GET /bundles/{bundleId}/items/{itemId}
 * Retrieves an item from a bundle
 */
exports.getBundleItem = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting item from bundle.' });
    },

    'application/json': () => {}

  });
};

/**
 * GET /{collection}
 * Retrieves items from a collection
 */
exports.getFromCollection = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting items from collection.' });
    },

    'application/json': () => {}

  });
};

/**
 * GET /{collection}/{itemId}
 * Retrieves a single item from a collection
 */
exports.getItem = (req, res) => {

  const errorHandler = err => {
    const errObj = r.convert(err);
    res.format({
      'text/html': () => res.render('error', errObj),
      'application/json': () => r.res(errObj, null, res)
    });
  };

  const successHandler = result => {
    if (result.permissions.public || (res.locals.user && res.locals.user.isViewer(result))) {
      res.format({
        'text/html': () => res.render('test', { test: JSON.stringify(strip(result), null, 2) }),
        'application/json': () => r.res(strip(result), 200, res)
      });
    } else {
      const errObj = r.json(res.locals.user ? 'User has insufficient permissions to access this resource.' : 'This is a private resource. Try logging in.', 403);
      res.format({
        'text/html': () => res.render('error', errObj),
        'application/json': () => r.res(errObj, null, res)
      });
    }
  };

  db.getById(req.params.collection, req.params.itemId)
  .then(successHandler)
  .catch(errorHandler);

};

/**
 * GET /lexicons/{lexiconId}/entries/{entryId}
 * Retrieves a lexicon entry from a lexicon
 */
exports.getLexEntry = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting lexicon entry.' });
    },

    'application/json': () => {}

  });
};

/**
 * GET /texts/{textId}/phrases/{phraseId}
 * Retrieves a phrase from a text
 */
exports.getPhrase = (req, res) => {
  res.format({

    'text/html': () => {
      res.render('test', { test: 'Getting phrase.' });
    },

    'application/json': () => {}

  });
};

/**
 * DELETE /bundles/{bundleId}/items/{itemId}
 * Removes an item from a bundle
 */
exports.removeBundleItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Deleting item from bundle.' });
  }
};

/**
 * POST /bundles/{bundleId}/items/{itemId}
 * Updates permissions or associated resources for a bundle item
 */
exports.updateBundleItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Updating bundle item.' });
  }
};

/**
 * POST /{collection}
 * Updates permissions or associated resources for multiple items in a collection
 */
exports.updateCollectionItems = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Updating collection items.' });
  }
};

/**
 * PUT /bundles/{bundleId}
 * Upserts an item to a bundle (and saves it to the appropriate collection)
 */
exports.upsertBundleItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Adding item to bundle.' });
  }
};

/**
 * POST /{collection}/{itemId}
 * Updates permissions or associated resources for an item
 */
exports.updateItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Updating item.' });
  }
};

/**
 * PUT /{collection}/{itemId}
 * Upserts an item to a collection
 */
exports.upsertItem = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Upserting item.' });
  }
};

/**
 * PUT /lexicons/{lexiconId}/entries/{entryId}
 * Upserts a lexicon entry to a lexicon
 */
exports.upsertLexEntry = (req, res) => {
  if (auth.checkToken(req, res)) {
    res.render('test', { test: 'Upserting lexicon entry.' });
  }
};

/**
 * POST /{collection}
 * Upserts items to a collection
 */
exports.upsertToCollection = (req, res) => {
  if (auth.checkToken(req, res)) {

    var isArr;
    const user = res.locals.user;

    const updateUser = results => new Promise((resolve, reject) => {
      isArr = results instanceof Array;
      if (isArr) { results.forEach(item => user.makeOwner(item)); }
      else { user.makeOwner(results); }
      db.upsert('users', user).then(() => resolve(results)).catch(reject);
    });

    db.upsert(req.params.collection, req.body)
    .then(updateUser)
    .then(results => {
      if (isArr) { r.res(results.map(strip), 201, res); }
      else { r.res(strip(results), 201, res); }
    })
    .catch(err => r.res(err, null, res));

  }
};
<|endoftext|>


<commit_before>$( ".topmenu ul" ).addClass('utama');
$( ".topmenu ul > li" ).addClass('prime');
$( ".topmenu ul > li > ul" ).addClass('sub');
$( ".topmenu ul > li > ul" ).removeClass('utama');

$( ".utama" ).appendTo( ".menu__wrap" );

var b = document.querySelector(".utama");
b.setAttribute("class", "menu__level");
b.setAttribute("aria-label", "All");
b.setAttribute("data-menu", "main");
b.setAttribute("role", "menu");
b.setAttribute("tabindex", "-1");

$('.parent a').each( function( index ) {

   $(this).addClass('dodol');
});

$("li .prime a").removeClass();

$('.sub').attr('aria-label', function() {
    return $(this).prev('.dodol').text();
});

$(".sub").each( function( index ) {
    $(this).attr("data-menu", "submenu-" + index);
	$(this).attr("id", "submenu-" + index);
	$(this).attr("class", "menu__level");
});
<commit_msg>Delete cust.js<commit_after><|endoftext|>


<commit_before>var url = require('url');
var http = require('http');
var https = require('https');
var stringify = require('json-stringify-safe');

exports.VERSION = '1';
exports.endpoint = 'https://api.rollbar.com/api/' + exports.VERSION + '/';
exports.accessToken = null;

var SETTINGS = {
  accessToken: null,
  protocol: 'https',
  endpoint: exports.endpoint,
  verbose: true
};

/*
 * Public API
 */

exports.init = function(accessToken, options) {
  options = options || {};
  exports.accessToken = accessToken;
  exports.endpoint = options.endpoint || exports.endpoint;

  for (var opt in options) {
    SETTINGS[opt] = options[opt];
  }

  SETTINGS.endpointOpts = url.parse(exports.endpoint);
  SETTINGS.protocol = SETTINGS.endpointOpts.protocol.split(':')[0];
  SETTINGS.transport = {http: http, https: https}[SETTINGS.protocol];

  var portCheck = SETTINGS.endpointOpts.host.split(':');
  if (portCheck.length > 1) {
    SETTINGS.endpointOpts.host = portCheck[0];
    SETTINGS.port = parseInt(portCheck[1]);
  }
};

exports.postItems = function(items, callback) {
  return postApi('items/', buildPayload(items), callback);
};

/** Internal **/

function getApi(path, params, callback) {
  var transport = SETTINGS.transport;
  var opts = transportOpts(path, 'GET');
  return makeApiRequest(transport, opts, null, callback);
}

function postApi(path, payload, callback) {
  var transport = SETTINGS.transport;
  var opts = transportOpts(path, 'POST');

  return makeApiRequest(transport, opts, payload, callback);
}

function makeApiRequest(transport, opts, bodyObj, callback) {
  var writeData = null;

  if (bodyObj) {
    try {
      try {
        writeData = JSON.stringify(bodyObj);
      } catch (e) {
        console.error('[Rollbar] Could not serialize to JSON - falling back to safe-stringify');
        writeData = stringify(bodyObj);
      }
    } catch(e) {
      console.error(e);
      return callback(e);
    }

    opts.headers = opts.headers || {};
    opts.headers['Content-Type'] = 'application/json';
    opts.headers['Content-Length'] = Buffer.byteLength(writeData, 'utf8');
  }
  var req = transport.request(opts, function(resp) {
    var respData = [];
    resp.setEncoding('utf8');
    resp.on('data', function(chunk) {
      respData.push(chunk);
    });

    resp.on('end', function() {
      respData = respData.join('');
      return parseApiResponse(respData, callback);
    });
  });

  req.on('error', function(err) {
    console.error('[Rollbar] Could not make request to rollbar, ' + err);
    return callback(err);
  });

  if (writeData) {
    req.write(writeData);
  }
  req.end();
}

function parseApiResponse(respData, callback) {
  try {
    respData = JSON.parse(respData);
  } catch (e) {
    console.error('[Rollbar] Could not parse api response, err: ' + e);
    return callback(e);
  }

  if (respData.err) {
    console.error('[Rollbar] Received error: ' + respData.message);
    return callback(new Error('Api error: ' + (respData.message || 'Unknown error')));
  } else {
    if (SETTINGS.verbose) {
      console.log('[Rollbar] Successful api response');
    }
    return callback(null, respData.result);
  }
}

function transportOpts(path, method) {
  return {
    host: SETTINGS.endpointOpts.host,
    port: SETTINGS.port ||
      (SETTINGS.protocol == 'http' ? 80 : (SETTINGS.protocol == 'https' ? 443 : undefined)),
    path: SETTINGS.endpointOpts.path + path,
    method: method
  };
}

function buildPayload(data) {
  var payload = {
    access_token: exports.accessToken,
    data: data
  };
  return payload;
}
<commit_msg>added support for http proxy<commit_after>var url = require('url');
var http = require('http');
var https = require('https');
var stringify = require('json-stringify-safe');

exports.VERSION = '1';
exports.endpoint = 'https://api.rollbar.com/api/' + exports.VERSION + '/';
exports.accessToken = null;

var SETTINGS = {
  accessToken: null,
  protocol: 'https',
  endpoint: exports.endpoint,
  verbose: true,
  proxy: null
};

/*
 * Public API
 */

exports.init = function(accessToken, options) {
  options = options || {};
  exports.accessToken = accessToken;
  exports.endpoint = options.endpoint || exports.endpoint;

  for (var opt in options) {
    SETTINGS[opt] = options[opt];
  }

  SETTINGS.endpointOpts = url.parse(exports.endpoint);
  SETTINGS.protocol = SETTINGS.endpointOpts.protocol.split(':')[0];
  SETTINGS.transport = {http: http, https: https}[SETTINGS.protocol];
  SETTINGS.proxy = options.proxy;

  var portCheck = SETTINGS.endpointOpts.host.split(':');
  if (portCheck.length > 1) {
    SETTINGS.endpointOpts.host = portCheck[0];
    SETTINGS.port = parseInt(portCheck[1]);
  }
};

exports.postItems = function(items, callback) {
  return postApi('items/', buildPayload(items), callback);
};

/** Internal **/

function getApi(path, params, callback) {
  var transport = SETTINGS.transport;
  var opts = transportOpts(path, 'GET');
  return makeApiRequest(transport, opts, null, callback);
}

function postApi(path, payload, callback) {
  var transport = SETTINGS.transport;
  var opts = transportOpts(path, 'POST');

  return makeApiRequest(transport, opts, payload, callback);
}

function makeApiRequest(transport, opts, bodyObj, callback) {
  var writeData = null;

  if (bodyObj) {
    try {
      try {
        writeData = JSON.stringify(bodyObj);
      } catch (e) {
        console.error('[Rollbar] Could not serialize to JSON - falling back to safe-stringify');
        writeData = stringify(bodyObj);
      }
    } catch(e) {
      console.error(e);
      return callback(e);
    }

    opts.headers = opts.headers || {};
    opts.headers['Content-Type'] = 'application/json';
    opts.headers['Content-Length'] = Buffer.byteLength(writeData, 'utf8');
  }

  if (SETTINGS.proxy) {
    opts.path = SETTINGS.protocol + '://' + opts.host + opts.path;
    opts.host = SETTINGS.proxy.host;
    opts.port = SETTINGS.proxy.port;
    transport = http;
  }

  var req = transport.request(opts, function(resp) {
    var respData = [];
    resp.setEncoding('utf8');
    resp.on('data', function(chunk) {
      respData.push(chunk);
    });

    resp.on('end', function() {
      respData = respData.join('');
      return parseApiResponse(respData, callback);
    });
  });

  req.on('error', function(err) {
    console.error('[Rollbar] Could not make request to rollbar, ' + err);
    return callback(err);
  });

  if (writeData) {
    req.write(writeData);
  }
  req.end();
}

function parseApiResponse(respData, callback) {
  try {
    respData = JSON.parse(respData);
  } catch (e) {
    console.error('[Rollbar] Could not parse api response, err: ' + e);
    return callback(e);
  }

  if (respData.err) {
    console.error('[Rollbar] Received error: ' + respData.message);
    return callback(new Error('Api error: ' + (respData.message || 'Unknown error')));
  } else {
    if (SETTINGS.verbose) {
      console.log('[Rollbar] Successful api response');
    }
    return callback(null, respData.result);
  }
}

function transportOpts(path, method) {
  return {
    host: SETTINGS.endpointOpts.host,
    port: SETTINGS.port ||
      (SETTINGS.protocol == 'http' ? 80 : (SETTINGS.protocol == 'https' ? 443 : undefined)),
    path: SETTINGS.endpointOpts.path + path,
    method: method
  };
}

function buildPayload(data) {
  var payload = {
    access_token: exports.accessToken,
    data: data
  };
  return payload;
}
<|endoftext|>


<commit_before>'use strict';

function clicked(){
    core_audio_start({
      'id': 'boop',
    });

    var element = document.getElementById('score');
    element.innerHTML = parseInt(
      element.innerHTML,
      10
    ) + 1;
    generate();
}

function clear_links(){
    // Remove all target links from text.
    document.getElementById('text-div').innerHTML = core_storage_data['text'];
}

function decisecond(){
    time = (time - .1).toFixed(1);

    document.getElementById('time').innerHTML = time;

    if(time <= 0){
        stop();
    }
}

function generate(){
    clear_links();
    var range = 0;
    // Generate a range of link-length that doesn't overwrite any HTML.
    do{
        range = core_random_integer({
          'max': core_storage_data['text'].length - core_storage_data['link-length'],
        });
    }while(core_storage_data['text'].substr(range, core_storage_data['link-length']).indexOf('<') !== -1
      || core_storage_data['text'].substr(range, core_storage_data['link-length']).indexOf('>') != -1);

    // Replace the text with the new target link in it.
    document.getElementById('text-div').innerHTML = core_storage_data['text'].substr(0, range)
      + '' + core_storage_data['text'].substr(range, core_storage_data['link-length']) + ''
      + core_storage_data['text'].substr(range + core_storage_data['link-length'], core_storage_data['text'].length - range);
}

function start(){
    core_storage_save();

    time = core_storage_data['time-max'];

    document.getElementById('score').innerHTML = 0;
    var element = document.getElementById('start-button');
    element.onclick = stop;
    element.value = 'End [ESC]';
    document.getElementById('time').innerHTML = time;
    document.getElementById('time-max-span').innerHTML = time;
    clear_links();
    generate();

    interval = window.setInterval(
      decisecond,
      100
    );
}

function stop(){
    window.clearInterval(interval);
    clear_links();

    var element = document.getElementById('start-button');
    element.onclick = start;
    element.value = 'Start [H]';
}

var interval = 0;
var time = 0;
<commit_msg>added partial core_html_modify() usage<commit_after>'use strict';

function clicked(){
    core_audio_start({
      'id': 'boop',
    });

    var element = document.getElementById('score');
    element.innerHTML = parseInt(
      element.innerHTML,
      10
    ) + 1;
    generate();
}

function clear_links(){
    // Remove all target links from text.
    document.getElementById('text-div').innerHTML = core_storage_data['text'];
}

function decisecond(){
    time = (time - .1).toFixed(1);

    document.getElementById('time').innerHTML = time;

    if(time <= 0){
        stop();
    }
}

function generate(){
    clear_links();
    var range = 0;
    // Generate a range of link-length that doesn't overwrite any HTML.
    do{
        range = core_random_integer({
          'max': core_storage_data['text'].length - core_storage_data['link-length'],
        });
    }while(core_storage_data['text'].substr(range, core_storage_data['link-length']).indexOf('<') !== -1
      || core_storage_data['text'].substr(range, core_storage_data['link-length']).indexOf('>') != -1);

    // Replace the text with the new target link in it.
    document.getElementById('text-div').innerHTML = core_storage_data['text'].substr(0, range)
      + '' + core_storage_data['text'].substr(range, core_storage_data['link-length']) + ''
      + core_storage_data['text'].substr(range + core_storage_data['link-length'], core_storage_data['text'].length - range);
}

function start(){
    core_storage_save();

    time = core_storage_data['time-max'];

    document.getElementById('score').innerHTML = 0;
    core_html_modify({
      'id': 'start-button',
      'properties': {
        'onclick': stop,
        'value': 'End [ESC]',
      },
    });
    document.getElementById('time').innerHTML = time;
    document.getElementById('time-max-span').innerHTML = time;
    clear_links();
    generate();

    interval = window.setInterval(
      decisecond,
      100
    );
}

function stop(){
    window.clearInterval(interval);
    clear_links();

    core_html_modify({
      'id': 'start-button',
      'properties': {
        'onclick': start,
        'value': 'Start [H]',
      },
    });
}

var interval = 0;
var time = 0;
<|endoftext|>


<commit_before>function Api (app) {
  this.app = app
  this.commands = {}
}

Api.prototype.transferPromiseness = function (target, promise) {
  var self = this

  self.app.client.transferPromiseness(target, promise)
  target.electron = {}

  Object.keys(this.commands).forEach(function (command) {
    var apiPath = self.commands[command]
    var api = target.electron

    apiPath.slice(0, -1).forEach(function (segment) {
      if (!api[segment]) api[segment] = {}
      api = api[segment]
    })

    api[apiPath[apiPath.length - 1]] = target[command].bind(target)
  })
}

Api.prototype.initialize = function () {
  var self = this
  return this.load(self.app).then(getResponseValue).then(function (api) {
    self.api = api
    self.app.electron = {}
    self.add(self.app.electron, [], api)

    // Add electron property to client prototype so promises can be chained
    Object.getPrototypeOf(self.app.client).electron = self.app.electron
  })
}

Api.prototype.load = function (app) {
  return app.client.execute(function () {
    function ignoreModule (moduleName) {
      switch (moduleName) {
        case 'deprecate':
        case 'deprecations':
        case 'hideInternalModules':
          return true
      }
      return false
    }

    function addProperties (parent, api) {
      Object.getOwnPropertyNames(parent).forEach(function (key) {
        if (ignoreModule(key)) return

        var module = parent[key]
        api[key] = {}

        Object.getOwnPropertyNames(module).forEach(function (moduleKey) {
          var value = module[moduleKey]
          if (typeof value === 'function') {
            api[key][moduleKey] = 'function'
          }
        })
      })
    }

    var electron = require('electron')
    var api = {}

    addProperties(electron, api)
    addProperties(electron.remote, api.remote)

    return api
  })
}

Api.prototype.add = function (parent, parentSegments, api) {
  var self = this
  var app = self.app

  Object.keys(api).forEach(function (key) {
    var segments = parentSegments.concat(key)
    var commandName = 'electron.' + segments.join('.')
    var value = api[key]

    if (value === 'function') {
      self.commands[commandName] = segments
      app.client.addCommand(commandName, function () {
        var args = Array.prototype.slice.call(arguments)
        return this.execute(callApi, segments, args).then(getResponseValue)
      })
      parent[key] = function () {
        return app.client[commandName].apply(app.client, arguments)
      }
    } else {
      parent[key] = {}
      self.add(parent[key], segments, value)
    }
  })
}

function callApi (segments, args) {
  var api = require('electron')

  segments.forEach(function (segment, index) {
    api = api[segment]
    if (api === 'function' && index < segments.length - 1) {
      api = api()
    }
  })

  return api.apply(api, args)
}

function getResponseValue (response) {
  return response.value
}

module.exports = Api
<commit_msg>Add app.browserWindow proxy<commit_after>function Api (app) {
  this.app = app
  this.commands = {}
}

Api.prototype.transferPromiseness = function (target, promise) {
  var self = this

  self.app.client.transferPromiseness(target, promise)
  target.electron = {}

  Object.keys(this.commands).forEach(function (command) {
    var apiPath = self.commands[command]
    var api = target.electron

    apiPath.slice(0, -1).forEach(function (segment) {
      if (!api[segment]) api[segment] = {}
      api = api[segment]
    })

    api[apiPath[apiPath.length - 1]] = target[command].bind(target)
  })
}

Api.prototype.initialize = function () {
  var self = this
  return this.load(self.app).then(getResponseValue).then(function (api) {
    self.app.electron = {}
    self.app.browserWindow = {}
    self.add(self.app.electron, [], api.electron)
    self.addBrowserWindowApis(api.browserWindow)

    // Add electron property to client prototype so promises can be chained
    Object.getPrototypeOf(self.app.client).electron = self.app.electron
    Object.getPrototypeOf(self.app.client).browserWindow = self.app.browserWindow
  })
}

Api.prototype.load = function (app) {
  return app.client.execute(function () {
    var electron = require('electron')

    function ignoreModule (moduleName) {
      switch (moduleName) {
        case 'deprecate':
        case 'deprecations':
        case 'hideInternalModules':
          return true
      }
      return false
    }

    function addProperties (parent, api) {
      Object.getOwnPropertyNames(parent).forEach(function (key) {
        if (ignoreModule(key)) return

        var module = parent[key]
        api[key] = {}

        Object.getOwnPropertyNames(module).forEach(function (moduleKey) {
          var value = module[moduleKey]
          if (typeof value === 'function') {
            api[key][moduleKey] = 'function'
          }
        })
      })
    }

    function addBrowserWindow (api) {
      var currentWindow = electron.remote.getCurrentWindow()
      for (var name in currentWindow) {
        var value = currentWindow[name]
        if (typeof value === 'function') {
          api[name] = 'function'
        }
      }
    }

    var api = {
      electron: {},
      browserWindow: {},
      webContents: {}
    }

    addProperties(electron, api.electron)
    addProperties(electron.remote, api.electron.remote)
    addBrowserWindow(api.browserWindow)

    return api
  })
}

Api.prototype.add = function (parent, parentSegments, api) {
  var self = this
  var app = self.app

  Object.keys(api).forEach(function (key) {
    var segments = parentSegments.concat(key)
    var commandName = 'electron.' + segments.join('.')
    var value = api[key]

    if (value === 'function') {
      self.commands[commandName] = segments
      app.client.addCommand(commandName, function () {
        var args = Array.prototype.slice.call(arguments)
        return this.execute(callApi, segments, args).then(getResponseValue)
      })
      parent[key] = function () {
        return app.client[commandName].apply(app.client, arguments)
      }
    } else {
      parent[key] = {}
      self.add(parent[key], segments, value)
    }
  })
}

Api.prototype.addBrowserWindowApis = function (api) {
  var app = this.app
  app.browserWindow = {}

  Object.keys(api).forEach(function (name) {
    var commandName = 'browserWindow.' + name

    app.client.addCommand(commandName, function () {
      var args = Array.prototype.slice.call(arguments)
      return this.execute(callBrowserWindowApi, name, args).then(getResponseValue)
    })

    app.browserWindow[name] = function () {
      return app.client[commandName].apply(app.client, arguments)
    }
  })
}

function callBrowserWindowApi (name, args) {
  var window = require('electron').remote.getCurrentWindow()
  return window[name].apply(window, args)
}

function callApi (segments, args) {
  var api = require('electron')

  segments.forEach(function (segment, index) {
    api = api[segment]
    if (api === 'function' && index < segments.length - 1) {
      api = api()
    }
  })

  return api.apply(api, args)
}

function getResponseValue (response) {
  return response.value
}

module.exports = Api
<|endoftext|>


<commit_before>/**
 * Helper "class" for accessing MediaWiki API and handling cookie-based session
 */
module.exports = (function() {
	// introspect package.json to get module version
	var VERSION = require('../package').version;

	// @see https://github.com/mikeal/request
	var request = require('request');

	// import deferred-js
	// @see https://github.com/heavylifters/deferred-js
	var Deferred = require('./deferred/deferred').Deferred;

	// wait x ms between HTTP requests
	var QUEUE_DELAY = 50;

	var api = function(options) {
		this.protocol = options.protocol || 'http';
		this.port = options.port || (this.protocol === 'https' ? 443 : 80);
		this.server = options.server;
		this.path = options.path;
		this.proxy = options.proxy;
		this.jar = request.jar(); // create new cookie jar for each instance

		this.debug = options.debug;

		// set up logging
		var winston = require('winston');
		this.logger = new (winston.Logger)();

		if (!options.silent) {
			// console logging
			this.logger.add(winston.transports.Console, {
				level: this.debug ? 'debug' : 'info'
			});
			this.logger.cli();

			// file logging
			var path = require('path'),
				fs = require('fs'),
				logDir = path.dirname(process.argv[1]) + '/log/',
				logFile = logDir + path.basename(process.argv[1], '.js') + '.log';

			if (fs.existsSync(logDir)) {
				this.logger.add(winston.transports.File, {
					colorize: true,
					filename: logFile,
					json: false,
					level: this.debug ? 'debug' : 'info'
				});
			}
		}

		// requests queue
		this.queue = [];
		this.queueItemId = 0;

		if (this.protocol === 'https') {
			this.http = require('https');
		} else {
			this.http = require('http');
		}
		this.formatUrl = require('url').format;

		this.userAgent = 'nodemw v' + VERSION + ' (node.js ' + process.version + '; ' + process.platform + ' ' + process.arch + ')';
		this.version = VERSION;

		this.info(process.argv.join(' '));
		this.info(this.userAgent);
		this.info('Using <' + this.protocol + '://' + this.server + ':' + this.port + this.path + '/api.php> as API entry point');
		this.info('----');
	};

	var doRequest = function(params, callback, method, promise) {
		var self = this,
			// store requested action - will be used when parsing a response
			actionName = params.action,
			// "request" options
			options = {
				method: method || 'GET',
				proxy: this.proxy || false,
				jar: this.jar,
				headers: {
					'User-Agent': this.userAgent
				}
			};

		// HTTP request parameters
		params = params || {};

		// force JSON format
		params.format = 'json';

		// handle uploads
		if (method === 'UPLOAD') {
			options.method = 'POST';

			var CRLF = "\r\n",
				postBody = [],
				boundary = 'nodemw' + Math.random().toString().substr(2);

			// encode each field
			Object.keys(params).forEach(function(fieldName) {
				var value = params[fieldName];

				postBody.push("--" + boundary);
				postBody.push(CRLF);

				if (typeof value === 'string') {
					// properly encode UTF8 in binary-safe POST data
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(new Buffer(value, 'utf8'));
				}
				else {
					// send attachment
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"foo\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(value);
				}

				postBody.push(CRLF);
			});

			postBody.push("--" + boundary + "--");

			// encode post data
			options.headers['content-type'] = 'multipart/form-data; boundary=' + boundary;
			options.body = postBody;

			params = {};
		}

		// form an URL to API
		options.url = this.formatUrl({
			protocol: this.protocol,
			port: this.port,
			hostname: this.server,
			pathname: this.path + '/api.php',
			query: (options.method === 'GET') ? params : {}
		});

		// POST all parameters (avoid "request string too long" errors)
		if (method === 'POST') {
			options.form = params;
		}

		this.logger.debug('API action: %s', actionName);
		this.logger.debug('%d/%d: %s <%s>', this.currentItemId + 1, this.queueItemId, options.method, options.url);
		if (options.form) this.logger.debug('POST fields: %s', Object.keys(options.form).join(', '));

		request(options, function(error, response, body) {
			if (error) {
				self.logger.error('Request to API failed: %s', error);

				throw 'Request to API failed: ' + error;
			}

			if (response.statusCode !== 200) {
				self.logger.error('Request to API failed: HTTP status code was %d for <%s>', response.statusCode, options.url);
				self.logger.data(new Error().stack);

				throw 'Request to API failed: HTTP status code was ' + response.statusCode;
			}

			// parse response
			var data,
				info,
				next;

			try {
				data = JSON.parse(body);
				info = data && data[actionName];
				next = data && data['query-continue'] && data['query-continue'][params.list];
			}
			catch(e) {
				self.logger.error('Error parsing JSON response: %s',  body);
				self.logger.data(body);

				throw 'Error parsing JSON response: ' + body;
			}

			if (data && !data.error) {
				if (typeof callback === 'function') {
					callback && callback(info, next, data);
				}
				promise.resolve({
					info: info,
					next: next,
					data: data
				});
			}
			else {
				self.logger.error('Error returned by API: %s',  data.error.info);
				self.logger.data(data.error);

				throw 'Error returned by API: ' + data.error.info;
			}
		});

		return promise;
	};

	// add a function to the queue
	var addToQueue = function(fn) {
		var promise = new Deferred();

		// add to the queue
		this.queue.push({
			id: this.queueItemId++,
			fn: fn,
			promise: promise
		});

		//this.logger.debug('Queue: added #%d item (reqs remaining: %d)', this.queueItemId, this.queue.length);

		// try to process this item (maybe this queue is inactive right now)
		processQueue.apply(this);

		return promise;
	};

	// process the first item in the queue and schedule next check
	var processQueue = function() {
		var self = this,
			item;

		// is queue running? this function will be called via setTimeout
		if (this.queueBusy === true) {
			return;
		}

		// get an item to process
		item = this.queue.shift();

		// the queue is empty
		if (typeof item === 'undefined') {
			return;
		}

		if (typeof item.fn !== 'function') {
			throw new Error('addToQueue() not provided with a function!');
		}

		this.queueBusy = true;

		item.promise.then(function(res) {
			// schedule next queue check
			setTimeout(function() {
				self.queueBusy = false;
				processQueue.apply(self);
			}, QUEUE_DELAY);

			return res;
		});

		this.currentItemId = item.id;

		// call the function and pass promise it should reject / resolve
		item.fn.call(this, item.promise);
	};

	// public interface
	api.prototype = {
		log: function() {
			this.logger.log.apply(this.logger, arguments);
		},

		info: function() {
			this.logger.info.apply(this.logger, arguments);
		},

		warn: function(msg, extra) {
			this.logger.warn.apply(this.logger, arguments);
		},

		error: function(msg, extra) {
			this.logger.error.apply(this.logger, arguments);
		},

		// adds request to the queue and returns a promise
		call: function(params, callback, method) {
			var self = this;

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				doRequest.apply(self, [params, callback, method, promise]);
			});
		},

		// fetch an external resource
		fetchUrl: function(url, encoding) {
			var self = this;
			encoding = encoding || 'utf-8';

			this.info("Fetching <%s> (as %s)...", url, encoding);

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				request({
					url: url,
					encoding: (encoding === 'binary') ? null : encoding
				}, function (error, response, body) {
					if (!error && response.statusCode === 200) {
						self.info('Fetched %s kB', (body.length/1024).toFixed(2));
						promise.resolve(body);
					}
					else {
						throw new Error('fetchUrl failed with ' + error);
					}
				});
			});
		}
	};

	return api;
}());
<commit_msg>Reject a promise instead of throwing an error<commit_after>/**
 * Helper "class" for accessing MediaWiki API and handling cookie-based session
 */
module.exports = (function() {
	// introspect package.json to get module version
	var VERSION = require('../package').version;

	// @see https://github.com/mikeal/request
	var request = require('request');

	// import deferred-js
	// @see https://github.com/heavylifters/deferred-js
	var Deferred = require('./deferred/deferred').Deferred;

	// wait x ms between HTTP requests
	var QUEUE_DELAY = 50;

	var api = function(options) {
		this.protocol = options.protocol || 'http';
		this.port = options.port || (this.protocol === 'https' ? 443 : 80);
		this.server = options.server;
		this.path = options.path;
		this.proxy = options.proxy;
		this.jar = request.jar(); // create new cookie jar for each instance

		this.debug = options.debug;

		// set up logging
		var winston = require('winston');
		this.logger = new (winston.Logger)();

		if (!options.silent) {
			// console logging
			this.logger.add(winston.transports.Console, {
				level: this.debug ? 'debug' : 'info'
			});
			this.logger.cli();

			// file logging
			var path = require('path'),
				fs = require('fs'),
				logDir = path.dirname(process.argv[1]) + '/log/',
				logFile = logDir + path.basename(process.argv[1], '.js') + '.log';

			if (fs.existsSync(logDir)) {
				this.logger.add(winston.transports.File, {
					colorize: true,
					filename: logFile,
					json: false,
					level: this.debug ? 'debug' : 'info'
				});
			}
		}

		// requests queue
		this.queue = [];
		this.queueItemId = 0;

		if (this.protocol === 'https') {
			this.http = require('https');
		} else {
			this.http = require('http');
		}
		this.formatUrl = require('url').format;

		this.userAgent = 'nodemw v' + VERSION + ' (node.js ' + process.version + '; ' + process.platform + ' ' + process.arch + ')';
		this.version = VERSION;

		this.info(process.argv.join(' '));
		this.info(this.userAgent);
		this.info('Using <' + this.protocol + '://' + this.server + ':' + this.port + this.path + '/api.php> as API entry point');
		this.info('----');
	};

	var doRequest = function(params, callback, method, promise) {
		var self = this,
			// store requested action - will be used when parsing a response
			actionName = params.action,
			// "request" options
			options = {
				method: method || 'GET',
				proxy: this.proxy || false,
				jar: this.jar,
				headers: {
					'User-Agent': this.userAgent
				}
			};

		// HTTP request parameters
		params = params || {};

		// force JSON format
		params.format = 'json';

		// handle uploads
		if (method === 'UPLOAD') {
			options.method = 'POST';

			var CRLF = "\r\n",
				postBody = [],
				boundary = 'nodemw' + Math.random().toString().substr(2);

			// encode each field
			Object.keys(params).forEach(function(fieldName) {
				var value = params[fieldName];

				postBody.push("--" + boundary);
				postBody.push(CRLF);

				if (typeof value === 'string') {
					// properly encode UTF8 in binary-safe POST data
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(new Buffer(value, 'utf8'));
				}
				else {
					// send attachment
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"foo\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(value);
				}

				postBody.push(CRLF);
			});

			postBody.push("--" + boundary + "--");

			// encode post data
			options.headers['content-type'] = 'multipart/form-data; boundary=' + boundary;
			options.body = postBody;

			params = {};
		}

		// form an URL to API
		options.url = this.formatUrl({
			protocol: this.protocol,
			port: this.port,
			hostname: this.server,
			pathname: this.path + '/api.php',
			query: (options.method === 'GET') ? params : {}
		});

		// POST all parameters (avoid "request string too long" errors)
		if (method === 'POST') {
			options.form = params;
		}

		this.logger.debug('API action: %s', actionName);
		this.logger.debug('%d/%d: %s <%s>', this.currentItemId + 1, this.queueItemId, options.method, options.url);
		if (options.form) this.logger.debug('POST fields: %s', Object.keys(options.form).join(', '));

		request(options, function(error, response, body) {
			if (error) {
				self.logger.error('Request to API failed: %s', error);

				promise.reject({
					err:'Request to API failed: ' + error,
					info: error
				});
			}

			if (response.statusCode !== 200) {
				self.logger.error('Request to API failed: HTTP status code was %d for <%s>', response.statusCode, options.url);
				self.logger.data(new Error().stack);

				promise.reject({
					err:'Request to API failed: HTTP status code was ' + response.statusCode,
					info: response
				});
			}

			// parse response
			var data,
				info,
				next;

			try {
				data = JSON.parse(body);
				info = data && data[actionName];
				next = data && data['query-continue'] && data['query-continue'][params.list];
			}
			catch(e) {
				self.logger.error('Error parsing JSON response: %s',  body);
				self.logger.data(body);

				promise.reject({
					err: 'Error parsing JSON response',
					info: data.body
				});
			}

			//if (!callback) data.error = {info: 'foo'}; // debug

			if (data && !data.error) {
				if (typeof callback === 'function') {
					callback && callback(info, next, data);
				}
				promise.resolve({
					info: info,
					next: next,
					data: data
				});
			}
			else {
				self.logger.error('Error returned by API: %s',  data.error.info);
				self.logger.data(data.error);

				promise.reject({
					err: 'Error returned by API: ' + data.error.info,
					info: data.error
				});
			}
		});

		return promise;
	};

	// add a function to the queue
	var addToQueue = function(fn) {
		var promise = new Deferred();

		// add to the queue
		this.queue.push({
			id: this.queueItemId++,
			fn: fn,
			promise: promise
		});

		//this.logger.debug('Queue: added #%d item (reqs remaining: %d)', this.queueItemId, this.queue.length);

		// try to process this item (maybe this queue is inactive right now)
		processQueue.apply(this);

		return promise;
	};

	// process the first item in the queue and schedule next check
	var processQueue = function() {
		var self = this,
			item;

		// is queue running? this function will be called via setTimeout
		if (this.queueBusy === true) {
			return;
		}

		// get an item to process
		item = this.queue.shift();

		// the queue is empty
		if (typeof item === 'undefined') {
			return;
		}

		if (typeof item.fn !== 'function') {
			throw new Error('addToQueue() not provided with a function!');
		}

		this.queueBusy = true;

		item.promise.both(function(res) {
			// schedule next queue check
			// both() adds both callback and errback
			setTimeout(function() {
				self.queueBusy = false;
				processQueue.apply(self);
			}, QUEUE_DELAY);

			return res;
		});

		this.currentItemId = item.id;

		// call the function and pass promise it should reject / resolve
		item.fn.call(this, item.promise);
	};

	// public interface
	api.prototype = {
		log: function() {
			this.logger.log.apply(this.logger, arguments);
		},

		info: function() {
			this.logger.info.apply(this.logger, arguments);
		},

		warn: function(msg, extra) {
			this.logger.warn.apply(this.logger, arguments);
		},

		error: function(msg, extra) {
			this.logger.error.apply(this.logger, arguments);
		},

		// adds request to the queue and returns a promise
		call: function(params, callback, method) {
			var self = this;

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				doRequest.apply(self, [params, callback, method, promise]);
			});
		},

		// fetch an external resource
		fetchUrl: function(url, encoding) {
			var self = this;
			encoding = encoding || 'utf-8';

			this.info("Fetching <%s> (as %s)...", url, encoding);

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				request({
					url: url,
					encoding: (encoding === 'binary') ? null : encoding
				}, function (error, response, body) {
					if (!error && response.statusCode === 200) {
						self.info('Fetched %s kB', (body.length/1024).toFixed(2));
						promise.resolve(body);
					}
					else {
						self.error('Failed to fetch <' + url + '>');
						promise.reject({
							err: 'fetchUrl failed with: ' + error,
							info: error
						});
					}
				});
			});
		}
	};

	return api;
}());
<|endoftext|>


<commit_before>//Licensed under the ISC license.
//Copyright 2014 Yuki Ahmed

var Router = require("express").Router,
    exml = require("easyxml").render;

var Api = function(entry, carry) {
  this.entry = entry;
  this.router = Router();
  this.endpoints = {};

  this.router.use(function(req, res, next) {
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Origin", "*");

    res._end = res.end;
    res.end = function(msg) {
      if(typeof msg == "object" && !Buffer.isBuffer(msg)) {
        if("error" in msg) {
          res.status = 500;
        }

        if(req.params.type$ == "json") {
          if(req.query.pretty !== undefined) {
            msg = JSON.stringify(msg, null, 2);
          } else {
            msg = JSON.stringify(msg);
          }
          res.header("Content-Type", "application/json");
        } else if(req.params.type$ == "jsonp") {
          var func = req.query.callback || req.url.split("/")[0].split(".")[0];

          msg = func + "("+JSON.stringify(msg)+")";
          res.header("Content-Type", "text/javascript");
        } else if(req.params.type$ == "xml") {
          msg = exml(msg);
          res.header("Content-Type", "application/xml");
        }
      }

      res._end(msg);
    }
    next();
  })
};

Api.prototype = {
  interface: function(interface) {
    interface.sudo();
    this.router.use(interface.router);
  },
  path: function(req, res) {
    res.end(this.endpoints);
  },
  getInterface: function(entry) {
    this.endpoints[entry] = {};
    return new Interface(entry, this);
  },
  sudo: function() {
    var entry = {};
    for(var key in this.endpoints) {
      var val = this.endpoints[val];
      if(typeof val == "string") {
        entry[key] = "/" + this.entry + "/" + val;
      } else {
        entry[key] = val;
        entry[key].url = "/" + this.entry + "/" + val;
      }
    };
    this.router.get("/", function(req, res) {
      res.end(entry);
    });
  },
  mesh: function(app) {
    this.sudo();
    app.use("/"+entry, this.router);
  }
}

var Interface = function(entry, host) {
  this.entry = host.entry + entry;
  this.router = router;
  this.host = host;
  this.endpoints = {};
  this.router.use(function(req, res, next) {
    res.___end = res.end;
    res.end = function(message, expiry) {
      res.setHeader("Cache-Control", "public, max-age=" + Math.floor(expiry/1000));
      res.setHeader("Expires", new Date(Date.now() + expiry).toUTCString());
      res.___end(message);
    };
    next();
  });
}

Interface.prototype = {
  getInterface: function(entry) {
    this.host.endpoints[this.entry][entry] = this.entry + "/" + entry + "/";
    this.endpoints[entry] = {};
    return new Intreface(entry, this);
  },
  sudo: function() {
    var entry = {};
    for(var key in this.endpoints) {
      var val = this.endpoints[val];
      if(typeof val == "string") {
        entry[key] = "/" + this.entry + "/" + val;
      } else {
        entry[key] = val;
      }
    };
    this.router.get("/", function(req, res) {
      res.end(entry);
    });
  },
  static: function(meta, method) {
    this.endpoints[method.endpoint] = {
      params: meta.params,
      method: (method || "get").toUpperCase(),
      expires: meta.expires
    }
  },
  get: function(meta, call) {
    this.call("get", meta, call);
  },
  post: function(meta, call) {
    this.call("post", meta, call);
  },
  put: function(meta, call) {
    this.call("put", meta, call);
  },
  delete: function(meta, call) {
    this.call("delete", meta, call);
  },
  head: function(meta, call) {
    this.call("head", meta, call);
  },
  call: function(method, meta, call) {
    this.static(meta, method);

    this.router[method]("/" + endpoint + ".:type$", call);
  }
}

exports = module.exports = Api;
exports.interface = module.exports.interface = Interface;
<commit_msg>.jsonp -> .js<commit_after>//Licensed under the ISC license.
//Copyright 2014 Yuki Ahmed

var Router = require("express").Router,
    exml = require("easyxml").render;

var Api = function(entry, carry) {
  this.entry = entry;
  this.router = Router();
  this.endpoints = {};

  this.router.use(function(req, res, next) {
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Origin", "*");

    res._end = res.end;
    res.end = function(msg) {
      if(typeof msg == "object" && !Buffer.isBuffer(msg)) {
        if("error" in msg) {
          res.status = 500;
        }

        if(req.params.type$ == "json") {
          if(req.query.pretty !== undefined) {
            msg = JSON.stringify(msg, null, 2);
          } else {
            msg = JSON.stringify(msg);
          }
          res.header("Content-Type", "application/json");
        } else if(req.params.type$ == "js") {
          var func = req.query.callback || req.url.split("/")[0].split(".")[0];

          msg = func + "("+JSON.stringify(msg)+")";
          res.header("Content-Type", "text/javascript");
        } else if(req.params.type$ == "xml") {
          msg = exml(msg);
          res.header("Content-Type", "application/xml");
        }
      }

      res._end(msg);
    }
    next();
  })
};

Api.prototype = {
  interface: function(interface) {
    interface.sudo();
    this.router.use(interface.router);
  },
  path: function(req, res) {
    res.end(this.endpoints);
  },
  getInterface: function(entry) {
    this.endpoints[entry] = {};
    return new Interface(entry, this);
  },
  sudo: function() {
    var entry = {};
    for(var key in this.endpoints) {
      var val = this.endpoints[val];
      if(typeof val == "string") {
        entry[key] = "/" + this.entry + "/" + val;
      } else {
        entry[key] = val;
        entry[key].url = "/" + this.entry + "/" + val;
      }
    };
    this.router.get("/", function(req, res) {
      res.end(entry);
    });
  },
  mesh: function(app) {
    this.sudo();
    app.use("/"+entry, this.router);
  }
}

var Interface = function(entry, host) {
  this.entry = host.entry + entry;
  this.router = router;
  this.host = host;
  this.endpoints = {};
  this.router.use(function(req, res, next) {
    res.___end = res.end;
    res.end = function(message, expiry) {
      res.setHeader("Cache-Control", "public, max-age=" + Math.floor(expiry/1000));
      res.setHeader("Expires", new Date(Date.now() + expiry).toUTCString());
      res.___end(message);
    };
    next();
  });
}

Interface.prototype = {
  getInterface: function(entry) {
    this.host.endpoints[this.entry][entry] = this.entry + "/" + entry + "/";
    this.endpoints[entry] = {};
    return new Intreface(entry, this);
  },
  sudo: function() {
    var entry = {};
    for(var key in this.endpoints) {
      var val = this.endpoints[val];
      if(typeof val == "string") {
        entry[key] = "/" + this.entry + "/" + val;
      } else {
        entry[key] = val;
      }
    };
    this.router.get("/", function(req, res) {
      res.end(entry);
    });
  },
  static: function(meta, method) {
    this.endpoints[method.endpoint] = {
      params: meta.params,
      method: (method || "get").toUpperCase(),
      expires: meta.expires
    }
  },
  get: function(meta, call) {
    this.call("get", meta, call);
  },
  post: function(meta, call) {
    this.call("post", meta, call);
  },
  put: function(meta, call) {
    this.call("put", meta, call);
  },
  delete: function(meta, call) {
    this.call("delete", meta, call);
  },
  head: function(meta, call) {
    this.call("head", meta, call);
  },
  call: function(method, meta, call) {
    this.static(meta, method);

    this.router[method]("/" + endpoint + ".:type$", call);
  }
}

exports = module.exports = Api;
exports.interface = module.exports.interface = Interface;
<|endoftext|>


<commit_before>// Right nav highlighting
var sidebarBottom = document.getElementsByClassName("sidebar")[0].getBoundingClientRect().bottom;
var footerTop = document.getElementsByClassName("footer")[0].getBoundingClientRect().top;
var headerOffset = document.getElementsByClassName("container-fluid")[0].getBoundingClientRect().bottom;

var x = document.links.length;
var baseHref = document.getElementsByTagName('base')[0].href
for (i = 0; i < x; i++) {
  var munged = false;
  var thisHREF = document.links[i].href;
  var originalURL = "{{ page.url }}";
  if (thisHREF.indexOf(baseHref + "#") > -1) {
    // hash fix
    //console.log('BEFORE: base:',baseHref,'thisHREF:',thisHREF,'originalURL:',originalURL);
    thisHREF = originalURL + thisHREF.replace(baseHref, "");
    //console.log('AFTER: base:',baseHref,'thisHREF:',thisHREF,'originalURL:',originalURL);
  }
  if ((thisHREF.indexOf(window.location.hostname) > -1 || thisHREF.indexOf('http') == -1) && document.links[i].className.indexOf("nomunge") < 0) {
    munged = true;
    thisHREF = thisHREF.replace(".md", "/").replace("/index/", "/");
    document.links[i].setAttribute('href', thisHREF);
  }
}

// ensure that the left nav visibly displays the current topic
var current = document.getElementsByClassName("active currentPage");
if (current[0]) {
    var container = document.getElementsByClassName("sidebar");
    if (container[0]) {
      current[0].scrollIntoView(true);
      container[0].scrollTop -= 150;
    }
  }

function highlightRightNav(heading)
{
  if (heading == "title")
  {
    history.replaceState({},"Top of page on " + document.location.pathname,document.location.protocol +"//"+ document.location.hostname + (location.port ? ':'+location.port: '') + document.location.pathname);
    $("#my_toc a").each(function(){
      $(this).removeClass("active");
    });
    $("#sidebar-wrapper").animate({
      scrollTop: 0
    },800);
  } else {
    var targetAnchorHREF = document.location.protocol +"//"+ document.location.hostname + (location.port ? ':'+location.port: '') + document.location.pathname + "#" + heading;
    // make sure we aren't filtering out that heading level
    var noFilterFound = false;
    $("#my_toc a").each(function(){
      if (this.href==targetAnchorHREF) {
        noFilterFound = true;
      }
    });
    // now, highlight that heading
    if (noFilterFound)
    {
      $("#my_toc a").each(function(){
        //console.log("right-nav",this.href);
        if (this.href==targetAnchorHREF)
        {
          history.replaceState({},this.innerText,targetAnchorHREF);
          $(this).addClass("active");
          var sidebarOffset = (sidebarBottom > 200) ? 200 : headerOffset - 20;
          $("#sidebar-wrapper").animate({
            scrollTop: $("#sidebar-wrapper").scrollTop() + $(this).position().top - sidebarOffset
          },100);
          //document.getElementById("sidebar-wrapper").scrollTop = this.getBoundingClientRect().top - 200;
        } else {
          $(this).removeClass("active");
        }
      });
    }
  }
}
function checkNavSizes()
{
  sidebarBottom = document.getElementsByClassName("sidebar")[0].getBoundingClientRect().bottom;
  footerTop = document.getElementsByClassName("footer")[0].getBoundingClientRect().top;
  headerOffset = document.getElementsByClassName("container-fluid")[0].getBoundingClientRect().bottom;
  if (footerTop < sidebarBottom || (sidebarBottom < footerTop && sidebarBottom < $(window).height()))
  {
    // the footer is overlapping the sidebar
    var sidebarHeight = ((footerTop - headerOffset) < $(window).height()) ? (footerTop - headerOffset) : $(window).height();
    var tocNavHeight = (footerTop < $(window).height()) ? footerTop : $(window).height();
    document.getElementsByClassName("sidebar")[0].style.height = sidebarHeight + "px";
    document.getElementsByClassName("toc-nav")[0].style.height = footerTop + "px";
    highlightRightNav(currentHeading);
  }
}
$(window).resize(function() {
  checkNavSizes();
});
var currentHeading = "";
$(window).scroll(function(){
  checkNavSizes();
  var headingPositions = new Array();
  $("h1, h2, h3, h4, h5, h6").each(function(){
    if (this.id == "") this.id="title";
    headingPositions[this.id]=this.getBoundingClientRect().top;
  });
  headingPositions.sort();
  // the headings have all been grabbed and sorted in order of their scroll
  // position (from the top of the page). First one is toppermost.
  for(var key in headingPositions)
  {
    if (headingPositions[key] > 0 && headingPositions[key] < 200)
    {
      if (currentHeading != key)
      {
        // a new heading has scrolled to within 200px of the top of the page.
        // highlight the right-nav entry and de-highlight the others.
        highlightRightNav(key);
        currentHeading = key;
      }
      break;
    }
  }
});

// Cookie functions
function createCookie(name,value,days) {
    var expires = "";
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days*24*60*60*1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + value + expires + "; path=/";
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name,"",-1);
}
/*
if (readCookie("night") == "true") {
  document.getElementById('pagestyle').setAttribute('href', '/css/style-alt.css');
  $('#switch-style').prop('checked', true);
} else {
  document.getElementById('pagestyle').setAttribute('href', '/css/style.css');
  $('#switch-style').prop('checked', false);
}
*/

/*
 *
 * toggle menu *********************************************************************
 *
 */

$("#menu-toggle").click(function(e) {
        e.preventDefault();
        $(".wrapper").toggleClass("right-open");
    });

var navHeight = $('.navbar').outerHeight(true) + 80;

$(document.body).scrollspy({
	target: '#leftCol',
	offset: navHeight
});

$(document).ready(function(){
  // Add smooth scrolling to all links
  // $( ".toc-nav a" ).addClass( "active" );
  $(".toc-nav a").on('click', function(event) {
    // $(this).addClass('active');
    // Make sure this.hash has a value before overriding default behavior
    if (this.hash !== "") {
      // Prevent default anchor click behavior
      event.preventDefault();

      // Store hash
      var hash = this.hash;

      // Using jQuery's animate() method to add smooth page scroll
      // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
      $('html, body').animate({
        scrollTop: $(hash).offset().top-80
      }, 800, function(){

        // Add hash (#) to URL when done scrolling (default click behavior)
        window.location.hash = hash;
      });
    } // End if
  });
});

$(document).ready(function(){
  // Add smooth scrolling to all links
  $(".nav-sidebar ul li a").on('click', function(event) {

    // Make sure this.hash has a value before overriding default behavior
    if (this.hash !== "") {
      // Prevent default anchor click behavior
      event.preventDefault();

      // Store hash
      var hash = this.hash;

      // Using jQuery's animate() method to add smooth page scroll
      // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
      $('html, body').animate({
        scrollTop: $(hash).offset().top-80
      }, 800, function(){

        // Add hash (#) to URL when done scrolling (default click behavior)
        window.location.hash = hash;
      });
    } // End if
  });
});

/*
 *
 * make dropdown show on hover *********************************************************************
 *
 */

$('ul.nav li.dropdown').hover(function() {
  $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(500);
}, function() {
  $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(500);
});

/*
 *
 * swapStyleSheet*********************************************************************
 *
 */

function swapStyleSheet(sheet) {
    document.getElementById('pagestyle').setAttribute('href', sheet);
}

$('#switch-style').change(function() {

    if ($(this).is(':checked')) {
        swapStyleSheet('/css/style-alt.css');
        createCookie("night",true,999)
    } else {
        swapStyleSheet('/css/style.css');
        eraseCookie("night")
    }
});

/*
 *
 * TEMP HACK For side menu*********************************************************************
 *
 */

$('.nav-sidebar ul li a').click(function() {
    $(this).addClass('collapse').siblings().toggleClass('in');
});

if($('.nav-sidebar ul a.active').length != 0)
{
  $('.nav-sidebar ul').click(function() {
      $(this).addClass('collapse in').siblings;
  });
}
<commit_msg>Fix for JS error on homepage<commit_after>// Right nav highlighting
var sidebarObj = (document.getElementsByClassName("sidebar")[0]) ? document.getElementsByClassName("sidebar")[0] : document.getElementsByClassName("sidebar-home")[0]
var sidebarBottom = sidebarObj.getBoundingClientRect().bottom;
var footerTop = document.getElementsByClassName("footer")[0].getBoundingClientRect().top;
var headerOffset = document.getElementsByClassName("container-fluid")[0].getBoundingClientRect().bottom;

var x = document.links.length;
var baseHref = document.getElementsByTagName('base')[0].href
for (i = 0; i < x; i++) {
  var munged = false;
  var thisHREF = document.links[i].href;
  var originalURL = "{{ page.url }}";
  if (thisHREF.indexOf(baseHref + "#") > -1) {
    // hash fix
    //console.log('BEFORE: base:',baseHref,'thisHREF:',thisHREF,'originalURL:',originalURL);
    thisHREF = originalURL + thisHREF.replace(baseHref, "");
    //console.log('AFTER: base:',baseHref,'thisHREF:',thisHREF,'originalURL:',originalURL);
  }
  if ((thisHREF.indexOf(window.location.hostname) > -1 || thisHREF.indexOf('http') == -1) && document.links[i].className.indexOf("nomunge") < 0) {
    munged = true;
    thisHREF = thisHREF.replace(".md", "/").replace("/index/", "/");
    document.links[i].setAttribute('href', thisHREF);
  }
}

// ensure that the left nav visibly displays the current topic
var current = document.getElementsByClassName("active currentPage");
if (current[0]) {
    if (sidebarObj) {
      current[0].scrollIntoView(true);
      container[0].scrollTop -= 150;
    }
  }

function highlightRightNav(heading)
{
  if (heading == "title")
  {
    history.replaceState({},"Top of page on " + document.location.pathname,document.location.protocol +"//"+ document.location.hostname + (location.port ? ':'+location.port: '') + document.location.pathname);
    $("#my_toc a").each(function(){
      $(this).removeClass("active");
    });
    $("#sidebar-wrapper").animate({
      scrollTop: 0
    },800);
  } else {
    var targetAnchorHREF = document.location.protocol +"//"+ document.location.hostname + (location.port ? ':'+location.port: '') + document.location.pathname + "#" + heading;
    // make sure we aren't filtering out that heading level
    var noFilterFound = false;
    $("#my_toc a").each(function(){
      if (this.href==targetAnchorHREF) {
        noFilterFound = true;
      }
    });
    // now, highlight that heading
    if (noFilterFound)
    {
      $("#my_toc a").each(function(){
        //console.log("right-nav",this.href);
        if (this.href==targetAnchorHREF)
        {
          history.replaceState({},this.innerText,targetAnchorHREF);
          $(this).addClass("active");
          var sidebarOffset = (sidebarBottom > 200) ? 200 : headerOffset - 20;
          $("#sidebar-wrapper").animate({
            scrollTop: $("#sidebar-wrapper").scrollTop() + $(this).position().top - sidebarOffset
          },100);
          //document.getElementById("sidebar-wrapper").scrollTop = this.getBoundingClientRect().top - 200;
        } else {
          $(this).removeClass("active");
        }
      });
    }
  }
}
function checkNavSizes()
{
  sidebarBottom = sidebarObj.getBoundingClientRect().bottom;
  footerTop = document.getElementsByClassName("footer")[0].getBoundingClientRect().top;
  headerOffset = document.getElementsByClassName("container-fluid")[0].getBoundingClientRect().bottom;
  if (footerTop < sidebarBottom || (sidebarBottom < footerTop && sidebarBottom < $(window).height()))
  {
    // the footer is overlapping the sidebar
    var sidebarHeight = ((footerTop - headerOffset) < $(window).height()) ? (footerTop - headerOffset) : $(window).height();
    var tocNavHeight = (footerTop < $(window).height()) ? footerTop : $(window).height();
    document.getElementsByClassName("sidebar")[0].style.height = sidebarHeight + "px";
    document.getElementsByClassName("toc-nav")[0].style.height = footerTop + "px";
    highlightRightNav(currentHeading);
  }
}
$(window).resize(function() {
  checkNavSizes();
});
var currentHeading = "";
$(window).scroll(function(){
  checkNavSizes();
  var headingPositions = new Array();
  $("h1, h2, h3, h4, h5, h6").each(function(){
    if (this.id == "") this.id="title";
    headingPositions[this.id]=this.getBoundingClientRect().top;
  });
  headingPositions.sort();
  // the headings have all been grabbed and sorted in order of their scroll
  // position (from the top of the page). First one is toppermost.
  for(var key in headingPositions)
  {
    if (headingPositions[key] > 0 && headingPositions[key] < 200)
    {
      if (currentHeading != key)
      {
        // a new heading has scrolled to within 200px of the top of the page.
        // highlight the right-nav entry and de-highlight the others.
        highlightRightNav(key);
        currentHeading = key;
      }
      break;
    }
  }
});

// Cookie functions
function createCookie(name,value,days) {
    var expires = "";
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days*24*60*60*1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + value + expires + "; path=/";
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name,"",-1);
}
/*
if (readCookie("night") == "true") {
  document.getElementById('pagestyle').setAttribute('href', '/css/style-alt.css');
  $('#switch-style').prop('checked', true);
} else {
  document.getElementById('pagestyle').setAttribute('href', '/css/style.css');
  $('#switch-style').prop('checked', false);
}
*/

/*
 *
 * toggle menu *********************************************************************
 *
 */

$("#menu-toggle").click(function(e) {
        e.preventDefault();
        $(".wrapper").toggleClass("right-open");
    });

var navHeight = $('.navbar').outerHeight(true) + 80;

$(document.body).scrollspy({
	target: '#leftCol',
	offset: navHeight
});

$(document).ready(function(){
  // Add smooth scrolling to all links
  // $( ".toc-nav a" ).addClass( "active" );
  $(".toc-nav a").on('click', function(event) {
    // $(this).addClass('active');
    // Make sure this.hash has a value before overriding default behavior
    if (this.hash !== "") {
      // Prevent default anchor click behavior
      event.preventDefault();

      // Store hash
      var hash = this.hash;

      // Using jQuery's animate() method to add smooth page scroll
      // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
      $('html, body').animate({
        scrollTop: $(hash).offset().top-80
      }, 800, function(){

        // Add hash (#) to URL when done scrolling (default click behavior)
        window.location.hash = hash;
      });
    } // End if
  });
});

$(document).ready(function(){
  // Add smooth scrolling to all links
  $(".nav-sidebar ul li a").on('click', function(event) {

    // Make sure this.hash has a value before overriding default behavior
    if (this.hash !== "") {
      // Prevent default anchor click behavior
      event.preventDefault();

      // Store hash
      var hash = this.hash;

      // Using jQuery's animate() method to add smooth page scroll
      // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
      $('html, body').animate({
        scrollTop: $(hash).offset().top-80
      }, 800, function(){

        // Add hash (#) to URL when done scrolling (default click behavior)
        window.location.hash = hash;
      });
    } // End if
  });
});

/*
 *
 * make dropdown show on hover *********************************************************************
 *
 */

$('ul.nav li.dropdown').hover(function() {
  $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(500);
}, function() {
  $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(500);
});

/*
 *
 * swapStyleSheet*********************************************************************
 *
 */

function swapStyleSheet(sheet) {
    document.getElementById('pagestyle').setAttribute('href', sheet);
}

$('#switch-style').change(function() {

    if ($(this).is(':checked')) {
        swapStyleSheet('/css/style-alt.css');
        createCookie("night",true,999)
    } else {
        swapStyleSheet('/css/style.css');
        eraseCookie("night")
    }
});

/*
 *
 * TEMP HACK For side menu*********************************************************************
 *
 */

$('.nav-sidebar ul li a').click(function() {
    $(this).addClass('collapse').siblings().toggleClass('in');
});

if($('.nav-sidebar ul a.active').length != 0)
{
  $('.nav-sidebar ul').click(function() {
      $(this).addClass('collapse in').siblings;
  });
}
<|endoftext|>