<commit_before>var CONFIG  = require("./config"),
    fs      = require("fs"),
    Client  = require("ftp"),
    Git     = require("nodegit"),
    del     = require("del"),
    unzip   = require("unzip"),
    logging = require("./logger")(true),
    sys     = require('sys'),
    exec    = require('child_process').exec

listPrimaryDirectory (function (latestFolder) {
  listSecondaryDirectory (latestFolder, function (c, pathToZip) {
    downloadZip (c, pathToZip, function () {
      updateGitFiles (function () {
        deleteRepoContents (function () {
          extractZipIntoRepo (function () {
            exec(
              "cd /tmp/ftp2git_repo && " +
              "git add . -A && " +
              "git commit -m \"update\" && " +
              "git push origin master"
            , puts)
          })
        })
      })
    })
  })
})

function puts(error, stdout, stderr) {
  logger.println ( sys.puts(stdout) )
}

function updateGitFiles (callback) {
  logging.print ("cloning/pulling repo ... ")

  exec(
    "cd /tmp && " +
    "git clone " + CONFIG.GIT_PATH + " /tmp/ftp2git_repo && " +
    "cd ftp2git_repo && " +
    "git pull"
  , function (error, stdout, stderr) {
    if (error) {
      logging.println ("ERROR" + error)
    }

    logging.println ("done")
    callback()
  })
}

function deleteRepoContents (callback) {
  logging.print ("Deleting old repo files and folders ... ")

  deleteFromFileSystem ("/tmp/ftp2git_repo/*", callback)
}

function deleteFromFileSystem (path, callback) {
  var delete_options = {
    force: true // allow access from outside directory running script (ie /tmp/)
  }

  del([path], delete_options, function (err, paths) {
    logging.println ("done")

    callback ()
  })
}

function extractZipIntoRepo (callback) {
  logging.print ("Extracting zip into repo ... ")

  fs.createReadStream("/tmp/ftp2git.zip")
    .pipe(unzip.Extract({ path: "/tmp/ftp2git_repo" }))
    .on("close", function () {
      logging.println ("done")

      callback ()
    })
}

function listPrimaryDirectory (callback) {
  var c = new Client()

  logging.print ("Listing primary dir ... ")
  c.on("ready", function() {
    c.list(function(err, list) {
      if (err) throw err

      c.end()

      var latestFolder = getLatestFolder (list)

      logging.println ("done")
      callback (latestFolder)
    })
  })

  c.connect(CONFIG.CLIENT_OPTIONS)
}

function listSecondaryDirectory (latestFolder, callback) {
  var c = new Client()

  logging.print ("Listing secondary dir ... ")
  c.on ("ready", function () {
    c.list(latestFolder, function(err, list) {
      if (err) throw err

      var pathToZip = latestFolder + "/" + getPathToZip (list)

      logging.println ("done")
      callback (c, pathToZip)
    })
  })

  c.connect (CONFIG.CLIENT_OPTIONS)
}

function downloadZip (c, pathToZip, callback) {
  logging.print ("downloading zip file ... ")

  c.get(pathToZip, function(err, stream) {
    if (err) throw err

    stream.once("close", function() {
      c.end()

      logging.println ("done")
      callback()
    })

    stream.pipe(fs.createWriteStream("/tmp/ftp2git.zip"))
  })
}

function getLatestFolder (list) {
  var latestFolder

  for (i in list) {
    var current_folder_name = list[i].name

    if (current_folder_name.indexOf(CONFIG.KEY_WORD) >= 0) {
      latestFolder = current_folder_name
    }
  }

  return latestFolder
}

function getPathToZip (list) {
  var pathToZip

  for (i in list) {
    var filename = list[i].name

    pathToZip = filename
  }

  return pathToZip
}<commit_msg>logging not logger<commit_after>var CONFIG  = require("./config"),
    fs      = require("fs"),
    Client  = require("ftp"),
    Git     = require("nodegit"),
    del     = require("del"),
    unzip   = require("unzip"),
    logging = require("./logger")(true),
    sys     = require('sys'),
    exec    = require('child_process').exec

listPrimaryDirectory (function (latestFolder) {
  listSecondaryDirectory (latestFolder, function (c, pathToZip) {
    downloadZip (c, pathToZip, function () {
      updateGitFiles (function () {
        deleteRepoContents (function () {
          extractZipIntoRepo (function () {
            exec(
              "cd /tmp/ftp2git_repo && " +
              "git add . -A && " +
              "git commit -m \"update\" && " +
              "git push origin master"
            , puts)
          })
        })
      })
    })
  })
})

function puts(error, stdout, stderr) {
  logging.println ( sys.puts(stdout) )
}

function updateGitFiles (callback) {
  logging.print ("cloning/pulling repo ... ")

  exec(
    "cd /tmp && " +
    "git clone " + CONFIG.GIT_PATH + " /tmp/ftp2git_repo && " +
    "cd ftp2git_repo && " +
    "git pull"
  , function (error, stdout, stderr) {
    if (error) {
      logging.println ("ERROR" + error)
    }

    logging.println ("done")
    callback()
  })
}

function deleteRepoContents (callback) {
  logging.print ("Deleting old repo files and folders ... ")

  deleteFromFileSystem ("/tmp/ftp2git_repo/*", callback)
}

function deleteFromFileSystem (path, callback) {
  var delete_options = {
    force: true // allow access from outside directory running script (ie /tmp/)
  }

  del([path], delete_options, function (err, paths) {
    logging.println ("done")

    callback ()
  })
}

function extractZipIntoRepo (callback) {
  logging.print ("Extracting zip into repo ... ")

  fs.createReadStream("/tmp/ftp2git.zip")
    .pipe(unzip.Extract({ path: "/tmp/ftp2git_repo" }))
    .on("close", function () {
      logging.println ("done")

      callback ()
    })
}

function listPrimaryDirectory (callback) {
  var c = new Client()

  logging.print ("Listing primary dir ... ")
  c.on("ready", function() {
    c.list(function(err, list) {
      if (err) throw err

      c.end()

      var latestFolder = getLatestFolder (list)

      logging.println ("done")
      callback (latestFolder)
    })
  })

  c.connect(CONFIG.CLIENT_OPTIONS)
}

function listSecondaryDirectory (latestFolder, callback) {
  var c = new Client()

  logging.print ("Listing secondary dir ... ")
  c.on ("ready", function () {
    c.list(latestFolder, function(err, list) {
      if (err) throw err

      var pathToZip = latestFolder + "/" + getPathToZip (list)

      logging.println ("done")
      callback (c, pathToZip)
    })
  })

  c.connect (CONFIG.CLIENT_OPTIONS)
}

function downloadZip (c, pathToZip, callback) {
  logging.print ("downloading zip file ... ")

  c.get(pathToZip, function(err, stream) {
    if (err) throw err

    stream.once("close", function() {
      c.end()

      logging.println ("done")
      callback()
    })

    stream.pipe(fs.createWriteStream("/tmp/ftp2git.zip"))
  })
}

function getLatestFolder (list) {
  var latestFolder

  for (i in list) {
    var current_folder_name = list[i].name

    if (current_folder_name.indexOf(CONFIG.KEY_WORD) >= 0) {
      latestFolder = current_folder_name
    }
  }

  return latestFolder
}

function getPathToZip (list) {
  var pathToZip

  for (i in list) {
    var filename = list[i].name

    pathToZip = filename
  }

  return pathToZip
}<|endoftext|>


<commit_before>/*
 * Taglist autocomplete wrapper for the Mine API, Richard Marr
 *
 * Based on jQuery Autocomplete plugin 1.1 by Jörn Zaefferer (c) 2009 Jörn Zaefferer
 * http://docs.jquery.com/Plugins/Autocomplete
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */

/**
 * TODO:
 * - bug: handle errors on ajax
 *  - like "your are not logged in"
 * - feature: delete tags
 * - feature: let the mine api do the filtering instead of the js
 * - feature: add new tag
 * - feature: show implied tags in tagcloud DONE
 * - feature: hide already selected tags in tagpicker
 *  - should also load implied tags for the existing tags
 */
;(function($) {

	// wrap the generic autocomplete functionality (which can be reused) with tag-list specific code
	// replace a input element with a nice tagpicker, the input element becomes a hidden one, which can just be posted
	var tagLister = new(function() {
		var that = this;
		var input;
		var hiddenInput;
		var ul;
		var tags;
		var tagRetreiver;

		$.extend(this, {
			init : function() {
				// "this" in this context is the element on which the tagLister is working
				var el = this;

				tags = that.extractExistingTags(el);
				that.replaceHTML(el);
				tagRetreiver = new that.TagRetreiver(that);
				that.addAutoCompleteBehaviour(input);
				return hiddenInput;
			},
			replaceHTML : function(el) {
				var attrs = {
					id      : el.attr("id"),
					name    : el.attr("name"),
					value   : tags.join(" "),
					"class" : el.attr("class"),
					size    : el.attr('size')
				}

				var i=1;
				while ($("#taglist"+i).length) {i++}
				var widgetId = "taglist"+i;

				el.replaceWith('
<input type="hidden" id="'+attrs.id+'" name="'+attrs.name+'" value="'+attrs.value+'" />
');
				hiddenInput = $("#"+widgetId+" input[type=hidden]");

				hiddenInput.after('<input type="text" class="'+attrs.class+'" size="'+attrs.size+'"/>');
				hiddenInput.before('

');

				input = $("#"+widgetId+" input[type=text]");
				ul = $("#"+widgetId+" ul");

				for (var i=0; i<tags.length; i++) {
					that.insertTagLi(tags[i]);
				}
			},
			extractExistingTags : function(el) {
				return that.splitTagString(el.attr("value"));
			},
			parseApiResult : function(data) {
				// opening the envelope
				// mapping data and value properties
				var result = [];
				for (var i=0; i<data.result.length; i++) {
					result[i] = data.result[i].tag;
					result[i].data = result[i].tagName;
					result[i].value = that.splitTagString(result[i].tagImplies)
				}
				return result;
			},
			addAutoCompleteBehaviour : function(input) {
				input.autocomplete(
					tagRetreiver.getTags,
					{
						minChars: 1,
						autoFill: false,
						mustMatch: false,
						cacheLength: 0,
						matchContains: true,
						scrollHeight: 220,
						formatItem: function(data, i, total, term) {
							return ""+data.tagName+" "+
								""+(data.tagImplies||"")+"";
						},
						parse : this.parseApiResult
					}
				).result(function(event, tag, implied) {
					// this is all kinda hacky; wheels will fall off this wagon
					if ($.inArray(tag, tags)==-1) {
						tags.push(tag);
						hiddenInput.attr("value", tags.join(" "));
						that.insertTagLi(tag, implied);
					}
					input.attr("value", "");
				});
			},
			insertTagLi : function(value, implied) {
				if (implied && implied.length) {
					ul.append('
'+value+' < '+implied.join(' ')+'
')
				} else {
					ul.append('
'+value+'
')
				}
			},
			filter : function() {
				return input.attr("value");
			},
			splitTagString : function(string) {
				return $.grep((string||"").split(/\s+/), function(s){return s!=""});
			},
			TagRetreiver : function(tagLister) {
					var completeResult = null;

					// assuming we're on the same domain, which is true for now
					var baseUrl = document.location.href.match(/[^:]+:\/\/[^\/]+/)[0];

					$.getJSON(
						baseUrl+"/api/tag.json",
						function(data) {
							completeResult = tagLister.parseApiResult(data);
						}
					);

					this.getTags = function() {
						if (!completeResult) {
							return [];
						}
						var filter = tagLister.filter();
						return $.grep(completeResult, function(entry) {
							return entry.tagName.indexOf(filter)==0;
						});
					}
				}
			}
		);
	})();

	$.fn.extend({taglist: tagLister.init});

})(jQuery);<commit_msg>tagwidget: new tags also get added; return doesn't submit the form anymore<commit_after>/*
 * Taglist autocomplete wrapper for the Mine API, Richard Marr
 *
 * Based on jQuery Autocomplete plugin 1.1 by Jörn Zaefferer (c) 2009 Jörn Zaefferer
 * http://docs.jquery.com/Plugins/Autocomplete
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */

/**
 * TODO:
 * - bug: handle errors on ajax
 *  - like "your are not logged in"
 * - feature: delete tags
 * - feature: let the mine api do the filtering instead of the js
 * - feature: add new tag
 * - feature: show implied tags in tagcloud DONE
 * - feature: hide already selected tags in tagpicker
 *  - should also load implied tags for the existing tags
 */
;(function($) {

	// wrap the generic autocomplete functionality (which can be reused) with tag-list specific code
	// replace a input element with a nice tagpicker, the input element becomes a hidden one, which can just be posted
	var tagLister = new(function() {
		var that = this;
		var input;
		var hiddenInput;
		var ul;
		var tags;
		var tagRetreiver;

				var KEY = {
					UP: 38,
					DOWN: 40,
					DEL: 46,
					TAB: 9,
					RETURN: 13,
					ESC: 27,
					COMMA: 188,
					PAGEUP: 33,
					PAGEDOWN: 34,
					BACKSPACE: 8
				};

		$.extend(this, {
			init : function() {
				// "this" in this context is the element on which the tagLister is working
				var el = this;

				tags = that.extractExistingTags(el);
				that.replaceHTML(el);
				tagRetreiver = new that.TagRetreiver(that);
				that.addAutoCompleteBehaviour(input);
				that.addKeyDownBehaviour(input);
				return hiddenInput;
			},
			replaceHTML : function(el) {
				var attrs = {
					id      : el.attr("id"),
					name    : el.attr("name"),
					value   : tags.join(" "),
					"class" : el.attr("class"),
					size    : el.attr('size')
				}

				var i=1;
				while ($("#taglist"+i).length) {i++}
				var widgetId = "taglist"+i;

				el.replaceWith('
<input type="hidden" id="'+attrs.id+'" name="'+attrs.name+'" value="'+attrs.value+'" />
');
				hiddenInput = $("#"+widgetId+" input[type=hidden]");

				hiddenInput.after('<input type="text" class="'+attrs.class+'" size="'+attrs.size+'"/>');
				hiddenInput.before('

');

				input = $("#"+widgetId+" input[type=text]");
				ul = $("#"+widgetId+" ul");

				for (var i=0; i<tags.length; i++) {
					that.insertTagLi(tags[i]);
				}
			},
			extractExistingTags : function(el) {
				return that.splitTagString(el.attr("value"));
			},
			parseApiResult : function(data) {
				// opening the envelope
				// mapping data and value properties
				var result = [];
				for (var i=0; i<data.result.length; i++) {
					result[i] = data.result[i].tag;
					result[i].data = result[i].tagName;
					result[i].value = that.splitTagString(result[i].tagImplies)
				}
				return result;
			},
			addAutoCompleteBehaviour : function(input) {
				input.autocomplete(
					tagRetreiver.getTags,
					{
						minChars: 1,
						autoFill: false,
						mustMatch: false,
						cacheLength: 0,
						matchContains: true,
						scrollHeight: 220,
						formatItem: function(data, i, total, term) {
							return ""+data.tagName+" "+
								""+(data.tagImplies||"")+"";
						},
						parse : this.parseApiResult
					}
				).result(function(event, tag, implied) {
					that.addTag(tag, implied);
					that.clearInput();
				});
			},
			clearInput : function(){
				input.attr("value", "");
			},
			insertTagLi : function(name, implied) {
				if (implied && implied.length) {
					ul.append('
'+name+' < '+implied.join(' ')+'
')
				} else {
					ul.append('
'+name+'
')
				}
			},
			filter : function() {
				return input.attr("value");
			},
			splitTagString : function(string) {
				return $.grep((string||"").split(/\s+/), function(s){return s!=""});
			},
			addKeyDownBehaviour : function(el) {
				el.bind("keydown", function(event) {
					switch(event.keyCode) {
						case KEY.RETURN:
							event.preventDefault();

							var filter = that.filter();
							if(filter) {
								that.addTag(filter);
								that.clearInput();
							}
							return false;
							break;
					}
				})

			},
			addTag : function(name, implied) {
				if ($.inArray(name, tags)==-1) {
					tags.push(name);
					hiddenInput.attr("value", tags.join(" "));
					that.insertTagLi(name, implied);
				}
			},
			TagRetreiver : function(tagLister) {
					var completeResult = null;

					// assuming we're on the same domain, which is true for now
					var baseUrl = document.location.href.match(/[^:]+:\/\/[^\/]+/)[0];

					$.getJSON(
						baseUrl+"/api/tag.json",
						function(data) {
							completeResult = tagLister.parseApiResult(data);
						}
					);

					this.getTags = function() {
						if (!completeResult) {
							return [];
						}
						var filter = tagLister.filter();
						return $.grep(completeResult, function(entry) {
							return entry.tagName.indexOf(filter)==0;
						});
					}
				}
			}
		);
	})();

	$.fn.extend({taglist: tagLister.init});

})(jQuery);<|endoftext|>


<commit_before>/**
 * @class C2
 * @description custom unit compressor with program-dependent action
 * @param {object} json parameters in JSON notation
 *                      { threshold, ratio, attack, release }
 */
WX.C2 = function(json) {
  // calling super constructor
  WX._Unit.call(this);
  // creating unit-specific properties
  Object.defineProperties(this, {
    _threshold: {
      enumerable: false,
      writable: true,
      value: WX.db2lin(-12.0)
    },
    _ratio: {
      enumerable: false,
      writable: true,
      value: 4.0
    },
    _iratio: {
      enumerable: false,
      writable: true,
      value: 1.0 / (this._ratio - 1.0)
    },
    _makeup: {
      enumerable: false,
      writable: true,
      value: WX.db2lin(0.0)
    },
    _detector: {
      enumerable: false,
      writable: false,
      value: new WX._Internals.DualLevelDetector()
    },
    _processor: {
      enumerable: false,
      writable: false,
      value: WX._context.createScriptProcessor(
          WX._customUnitBufferSize, 2, 2
        )
    }
  });
  var me = this;
  this._processor.onaudioprocess = function(event) {
    me._callback(event);
  };
  // performing unit-specific actions
  this._inlet.connect(this._processor);
  this._processor.connect(this._outlet);
  // assign (default) parameters
  this.params = json;
};

WX.C2.prototype = Object.create(WX._Unit.prototype, {

  /**
   * callback for onaudioprocess
   * @param {object} event
   */
  _callback: {
    value: function(event) {
      // temp vars
      var level, leveldB, gain, gaindB, delta;
      // input and output array buffer
      var inputL = event.inputBuffer.getChannelData(0);
      var inputR = event.inputBuffer.getChannelData(1);
      var outputL = event.outputBuffer.getChannelData(0);
      var outputR = event.outputBuffer.getChannelData(1);
      // callback loop
      for (var i = 0, b = WX._customUnitBufferSize; i < b; ++i) {
        // get abs-max from stereo
        var s = Math.max(Math.abs(inputL[i]), Math.abs(inputR[i]));
        // peak detection
        level = this._detector.process(s);
        // gain computer: compression with ratio
        delta = WX.lin2db(level / this._threshold);
        gaindB = (delta <= 0.0) ? 0.0 : delta * this._iratio;
        // gain computer: limiting
        // gaindB = Math.min(0.0, WX.lin2db(this._threshold / level));
        // get linear gain
        gain = WX.db2lin(gaindB);
        // compute output
        outputL[i] = inputL[i] * gain * this._makeup;
        outputR[i] = inputR[i] * gain * this._makeup;
      }
    }
  },

  /**
   * get/set threshold
   * @param {float} dB for user, linear for internal processing
   */
  threshold: {
    enumerable: true,
    get: function() {
      return WX.lin2db(this._threshold);
    },
    set: function(value) {
      this._threshold = WX.db2lin(value);
    }
  },

  /**
   * get/set ratio
   * @param {float} value arbitrary ratio
   */
  ratio: {
    enumerable: true,
    get: function() {
      return this._ratio;
    },
    set: function(value) {
      this._ratio = value;
      this._iratio = 1.0 / (this._ratio - 1.0);
    }
  },

  /**
   * get/set attack
   * @param {float} value attack in seconds
   */
  attack: {
    enumerable: true,
    get: function() {
      return this._detector.attack;
    },
    set: function(value) {
      this._detector.attack = value;
    }
  },

  /**
   * get/set release
   * @param {float} value release in seconds
   */
  release: {
    enumerable: true,
    get: function() {
      return this._detector.release;
    },
    set: function(value) {
      this._detector.release = value;
    }
  }
});<commit_msg>patched C2 ratio bug<commit_after>/**
 * @class C2
 * @description custom unit compressor with program-dependent action
 * @param {object} json parameters in JSON notation
 *                      { threshold, ratio, attack, release }
 */
WX.C2 = function(json) {
  // calling super constructor
  WX._Unit.call(this);
  // creating unit-specific properties
  Object.defineProperties(this, {
    _threshold: {
      enumerable: false,
      writable: true,
      value: WX.db2lin(-12.0)
    },
    _ratio: {
      enumerable: false,
      writable: true,
      value: 4.0
    },
    _iratio: {
      enumerable: false,
      writable: true,
      value: 1.0 / (this._ratio - 1.0)
    },
    _makeup: {
      enumerable: false,
      writable: true,
      value: WX.db2lin(0.0)
    },
    _detector: {
      enumerable: false,
      writable: false,
      value: new WX._Internals.DualLevelDetector()
    },
    _processor: {
      enumerable: false,
      writable: false,
      value: WX._context.createScriptProcessor(
          WX._customUnitBufferSize, 2, 2
        )
    }
  });
  var me = this;
  this._processor.onaudioprocess = function(event) {
    me._callback(event);
  };
  // performing unit-specific actions
  this._inlet.connect(this._processor);
  this._processor.connect(this._outlet);
  // assign (default) parameters
  this.params = json;
};

WX.C2.prototype = Object.create(WX._Unit.prototype, {

  /**
   * callback for onaudioprocess
   * @param {object} event
   */
  _callback: {
    value: function(event) {
      // temp vars
      var level, leveldB, gain, gaindB, delta;
      // input and output array buffer
      var inputL = event.inputBuffer.getChannelData(0);
      var inputR = event.inputBuffer.getChannelData(1);
      var outputL = event.outputBuffer.getChannelData(0);
      var outputR = event.outputBuffer.getChannelData(1);
      // callback loop
      for (var i = 0, b = WX._customUnitBufferSize; i < b; ++i) {
        // get abs-max from stereo
        var s = Math.max(Math.abs(inputL[i]), Math.abs(inputR[i]));
        // peak detection
        level = this._detector.process(s);
        // gain computer: compression with ratio
        delta = WX.lin2db(level / this._threshold);
        gaindB = (delta <= 0.0) ? 0.0 : delta * this._iratio;
        // gain computer: limiting
        // gaindB = Math.min(0.0, WX.lin2db(this._threshold / level));
        // get linear gain
        gain = WX.db2lin(gaindB);
        // compute output
        outputL[i] = inputL[i] * gain * this._makeup;
        outputR[i] = inputR[i] * gain * this._makeup;
      }
    }
  },

  /**
   * get/set threshold
   * @param {float} dB for user, linear for internal processing
   */
  threshold: {
    enumerable: true,
    get: function() {
      return WX.lin2db(this._threshold);
    },
    set: function(value) {
      this._threshold = WX.db2lin(value);
    }
  },

  /**
   * get/set ratio
   * @param {float} value arbitrary ratio
   */
  ratio: {
    enumerable: true,
    get: function() {
      return this._ratio;
    },
    set: function(value) {
      this._ratio = value;
      this._iratio = 1.0 / (this._ratio - 1.0);
    }
  },

  /**
   * get/set attack
   * @param {float} value attack in seconds
   */
  attack: {
    enumerable: true,
    get: function() {
      return this._detector.attack;
    },
    set: function(value) {
      this._detector.attack = value;
    }
  },

  /**
   * get/set release
   * @param {float} value release in seconds
   */
  release: {
    enumerable: true,
    get: function() {
      return this._detector.release;
    },
    set: function(value) {
      this._detector.release = value;
    }
  },

  /**
   * get/set makeup
   * @param {float} makeup gain in decibel
   */
  makeup: {
    enumerable: true,
    get: function() {
      return WX.lin2db(this._makeup);
    },
    set: function(value) {
      this._makeup = WX.db2lin(value);
    }
  }
});<|endoftext|>


<commit_before>/**********************************************************************
    Freeciv-web - the web version of Freeciv. http://play.freeciv.org/
    Copyright (C) 2009-2015  The Freeciv-web project

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************/

var error_shown = false;
var syncTimerId = -1;

var clinet_last_send = 0;
var debug_client_speed_list = [];

var freeciv_version = "+Freeciv.Web.Devel-3.0";

var ws = null;
var civserverport = null;

var ping_last = new Date().getTime();
var pingtime_check = 240000;

/****************************************************************************
  Initialized the Network communication, by requesting a valid server port.
****************************************************************************/
function network_init()
{

  if (!("WebSocket" in window)) {
    swal("WebSockets not supported", "", "error");
    return;
  }

  var civclient_request_url = "/civclientlauncher";
  if ($.getUrlVar('action') != null) civclient_request_url += "?action=" + $.getUrlVar('action');
  if ($.getUrlVar('action') == null && $.getUrlVar('civserverport') != null) civclient_request_url += "?";
  if ($.getUrlVar('civserverport') != null) civclient_request_url += "&civserverport=" + $.getUrlVar('civserverport');

  $.ajax({
   type: 'POST',
   url: civclient_request_url,
   success: function(data, textStatus, request){
       civserverport = request.getResponseHeader('port');
       var connect_result = request.getResponseHeader('result');
       if (civserverport != null && connect_result == "success") {
         websocket_init();
         load_game_check();

       } else {
         show_dialog_message("Network error", "Invalid server port. Error: " + connect_result);
       }
   },
   error: function (request, textStatus, errorThrown) {
	show_dialog_message("Network error", "Unable to communicate with civclientlauncher servlet . Error: "
		+ textStatus + " " + errorThrown + " " + request.getResponseHeader('result'));
   }
  });

  setInterval(ping_check, pingtime_check);

}

/****************************************************************************
  Initialized the WebSocket connection.
****************************************************************************/
function websocket_init()
{
  $.blockUI({ message: "
Please wait while connecting to the server.
" });
  var proxyport = 1000 + parseFloat(civserverport);
  var ws_protocol = ('https:' == window.location.protocol) ? "wss://" : "ws://";
  var port = window.location.port ? (':' + window.location.port) : '';
  ws = new WebSocket(ws_protocol + window.location.hostname + port + "/civsocket/" + proxyport);

  ws.onopen = check_websocket_ready;

  ws.onmessage = function (event) {
     if (typeof client_handle_packet !== 'undefined') {
       client_handle_packet(jQuery.parseJSON(event.data));
     } else {
       console.error("Error, freeciv-web not compiled correctly. Please "
             + "run sync.sh in freeciv-proxy correctly.");
     }
  };

  ws.onclose = function (event) {
   add_chatbox_text("Error: connection to server is closed. Please reload the page to restart. Sorry!");
   console.info("WebSocket connection closed, code+reason: " + event.code + ", " + event.reason);
   $("#turn_done_button").button( "option", "disabled", true);
   $("#save_button").button( "option", "disabled", true);
   pbem_phase_ended = true;
  };

  ws.onerror = function (evt) {
   show_dialog_message("Network error", "A problem occured with the "
                       + document.location.protocol + " WebSocket connection to the server: " + ws.url);
   console.error("WebSocket error: Unable to communicate with server using "
                 + document.location.protocol + " WebSockets. Error: " + evt);
  };
}

/****************************************************************************
  When the WebSocket connection is open and ready to communicate, then
  send the first login message to the server.
****************************************************************************/
function check_websocket_ready()
{
  if (ws != null && ws.readyState === 1) {
    var login_message = {"pid":4, "username" : username,
    "capability": freeciv_version, "version_label": "-dev",
    "major_version" : 2, "minor_version" : 5, "patch_version" : 99,
    "port": civserverport};
    ws.send(JSON.stringify(login_message));
    $.unblockUI();
  } else {
    setTimeout(check_websocket_ready, 500);
  }

}

/****************************************************************************
  Stops network sync.
****************************************************************************/
function network_stop()
{
  if (ws != null) ws.close();
  ws = null;
}

/****************************************************************************
  Sends a request to the server, with a JSON packet.
****************************************************************************/
function send_request(packet_payload)
{
  if (ws != null) {
    ws.send(packet_payload);
  }

  if (debug_active) {
    clinet_last_send = new Date().getTime();
  }
}

/****************************************************************************
...
****************************************************************************/
function clinet_debug_collect()
{
  var time_elapsed = new Date().getTime() - clinet_last_send;
  debug_client_speed_list.push(time_elapsed);
  clinet_last_send = new Date().getTime();
}

/****************************************************************************
  Detect server disconnections, by checking the time since the last
  ping packet from the server.
****************************************************************************/
function ping_check()
{
  var time_since_last_ping = new Date().getTime() - ping_last;
  if (time_since_last_ping > pingtime_check) {
    console.log("Error: Missing PING message from server, "
                + "indicates server connection problem.");
  }
}

/****************************************************************************
  send the chat message to the server after a delay.
****************************************************************************/
function send_message_delayed(message, delay)
{
  setTimeout("send_message('" + message + "');", delay);
}

/****************************************************************************
  sends a chat message to the server.
****************************************************************************/
function send_message(message)
{
  if (is_longturn() && message != null
      && message.indexOf(encodeURIComponent("/")) == -1
      && message.indexOf("/") == -1
      && message.trim().charAt(0) !== "."
      && message.indexOf(encodeURIComponent(":")) == -1) {
      message = username + " : " + message;
    }

  var packet = {"pid" : packet_chat_msg_req,
                "message" : message};
  send_request(JSON.stringify(packet));
}
<commit_msg>Stop "anonymous" chatbox fun in longturn.<commit_after>/**********************************************************************
    Freeciv-web - the web version of Freeciv. http://play.freeciv.org/
    Copyright (C) 2009-2015  The Freeciv-web project

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************/

var error_shown = false;
var syncTimerId = -1;

var clinet_last_send = 0;
var debug_client_speed_list = [];

var freeciv_version = "+Freeciv.Web.Devel-3.0";

var ws = null;
var civserverport = null;

var ping_last = new Date().getTime();
var pingtime_check = 240000;

/****************************************************************************
  Initialized the Network communication, by requesting a valid server port.
****************************************************************************/
function network_init()
{

  if (!("WebSocket" in window)) {
    swal("WebSockets not supported", "", "error");
    return;
  }

  var civclient_request_url = "/civclientlauncher";
  if ($.getUrlVar('action') != null) civclient_request_url += "?action=" + $.getUrlVar('action');
  if ($.getUrlVar('action') == null && $.getUrlVar('civserverport') != null) civclient_request_url += "?";
  if ($.getUrlVar('civserverport') != null) civclient_request_url += "&civserverport=" + $.getUrlVar('civserverport');

  $.ajax({
   type: 'POST',
   url: civclient_request_url,
   success: function(data, textStatus, request){
       civserverport = request.getResponseHeader('port');
       var connect_result = request.getResponseHeader('result');
       if (civserverport != null && connect_result == "success") {
         websocket_init();
         load_game_check();

       } else {
         show_dialog_message("Network error", "Invalid server port. Error: " + connect_result);
       }
   },
   error: function (request, textStatus, errorThrown) {
	show_dialog_message("Network error", "Unable to communicate with civclientlauncher servlet . Error: "
		+ textStatus + " " + errorThrown + " " + request.getResponseHeader('result'));
   }
  });

  setInterval(ping_check, pingtime_check);

}

/****************************************************************************
  Initialized the WebSocket connection.
****************************************************************************/
function websocket_init()
{
  $.blockUI({ message: "
Please wait while connecting to the server.
" });
  var proxyport = 1000 + parseFloat(civserverport);
  var ws_protocol = ('https:' == window.location.protocol) ? "wss://" : "ws://";
  var port = window.location.port ? (':' + window.location.port) : '';
  ws = new WebSocket(ws_protocol + window.location.hostname + port + "/civsocket/" + proxyport);

  ws.onopen = check_websocket_ready;

  ws.onmessage = function (event) {
     if (typeof client_handle_packet !== 'undefined') {
       client_handle_packet(jQuery.parseJSON(event.data));
     } else {
       console.error("Error, freeciv-web not compiled correctly. Please "
             + "run sync.sh in freeciv-proxy correctly.");
     }
  };

  ws.onclose = function (event) {
   add_chatbox_text("Error: connection to server is closed. Please reload the page to restart. Sorry!");
   console.info("WebSocket connection closed, code+reason: " + event.code + ", " + event.reason);
   $("#turn_done_button").button( "option", "disabled", true);
   $("#save_button").button( "option", "disabled", true);
   pbem_phase_ended = true;
  };

  ws.onerror = function (evt) {
   show_dialog_message("Network error", "A problem occured with the "
                       + document.location.protocol + " WebSocket connection to the server: " + ws.url);
   console.error("WebSocket error: Unable to communicate with server using "
                 + document.location.protocol + " WebSockets. Error: " + evt);
  };
}

/****************************************************************************
  When the WebSocket connection is open and ready to communicate, then
  send the first login message to the server.
****************************************************************************/
function check_websocket_ready()
{
  if (ws != null && ws.readyState === 1) {
    var login_message = {"pid":4, "username" : username,
    "capability": freeciv_version, "version_label": "-dev",
    "major_version" : 2, "minor_version" : 5, "patch_version" : 99,
    "port": civserverport};
    ws.send(JSON.stringify(login_message));
    $.unblockUI();
  } else {
    setTimeout(check_websocket_ready, 500);
  }

}

/****************************************************************************
  Stops network sync.
****************************************************************************/
function network_stop()
{
  if (ws != null) ws.close();
  ws = null;
}

/****************************************************************************
  Sends a request to the server, with a JSON packet.
****************************************************************************/
function send_request(packet_payload)
{
  if (ws != null) {
    ws.send(packet_payload);
  }

  if (debug_active) {
    clinet_last_send = new Date().getTime();
  }
}

/****************************************************************************
...
****************************************************************************/
function clinet_debug_collect()
{
  var time_elapsed = new Date().getTime() - clinet_last_send;
  debug_client_speed_list.push(time_elapsed);
  clinet_last_send = new Date().getTime();
}

/****************************************************************************
  Detect server disconnections, by checking the time since the last
  ping packet from the server.
****************************************************************************/
function ping_check()
{
  var time_since_last_ping = new Date().getTime() - ping_last;
  if (time_since_last_ping > pingtime_check) {
    console.log("Error: Missing PING message from server, "
                + "indicates server connection problem.");
  }
}

/****************************************************************************
  send the chat message to the server after a delay.
****************************************************************************/
function send_message_delayed(message, delay)
{
  setTimeout("send_message('" + message + "');", delay);
}

/****************************************************************************
  sends a chat message to the server.
****************************************************************************/
function send_message(message)
{
  if (is_longturn() && message != null) {
    if (message.indexOf(encodeURIComponent("/")) !== 0
      && message.indexOf("/") !== 0
      && message.charAt(0) !== ".") {
      var private_mark_i = message.indexOf(encodeURIComponent(":"));
      if (private_mark_i <= 0) {
        message = username + " : " + message;
      } else {
        var first_space = message.indexOf(encodeURIComponent(" "));
        if (first_space >= 0 && first_space < private_mark_i) {
          message = username + " : " + message;
        }
      }
    }
  }

  var packet = {"pid" : packet_chat_msg_req,
                "message" : message};
  send_request(JSON.stringify(packet));
}
<|endoftext|>


<commit_before>module.exports = function(app, db, env) {
	var url = require('url');
	var ldp = require('./vocab/ldp.js');			// LDP vocabulary
	var rdf = require('./vocab/rdf.js');			// RDF vocabulary
	var media = require('./media.js');				// media types
	var N3 = require('n3');
	var crypto = require('crypto');					// for MD5 (ETags)

	// route any requests matching /r/*
	var resource = app.route(env.context + '*');
	resource.all(function(req, res, next) {
		// all responses should have Link: <ldp:Resource> rel=type
		res.links({
			type: ldp.Resource
		});
		next();
	});

	function get(req, res, includeBody) {
		db.get(req.fullURL, function(err, document) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			if (document.deleted) {
				res.send(410);
				return;
			}

			if (!document.triples) {
				res.send(404);
				return;
			}

			if (!req.accepts(media.turtle)) {
				res.send(406);
				return;
			}

			addHeaders(res, document.interactionModel);
			addContainment(req, document, function(err) {
				if (err) {
					console.log(err.stack);
					res.send(500);
					return;
				}

				asTurtle(document.triples, function(err, turtle) {
					if (err) {
						res.send(500);
					} else {
						var eTag = getETag(turtle);
						if (req.get('If-None-Match') === eTag) {
							res.send(304);
							return;
						}

						res.writeHead(200, { 'ETag': eTag, 'Content-Type': media.turtle });
						if (includeBody) {
							res.end(new Buffer(turtle), 'utf-8');
						} else {
							res.end();
						}
					}
				});
			});
		});
	}

	resource.get(function(req, res, next) {
		console.log('GET ' + req.path);
		get(req, res, true);
	});

	resource.head(function(req, res, next) {
		console.log('HEAD ' + req.path);
		get(req, res, false);
	});

	resource.put(function(req, res, next) {
		console.log('PUT ' + req.path);
		if (!req.is('text/turtle')) {
			res.send(415);
			return;
		}

		parse(req, req.fullURL, function(err, triples, interactionModel) {
			if (err) {
				res.send(400);
				return;
			}

			// get the resource to check if it exists and check its ETag
			db.get(req.fullURL, function(err, original) {
				if (original) {
					if (original.deleted) {
						res.send(410);
						return;
					}

					// update
					var ifMatch = req.get('If-Match');
					if (!ifMatch) {
						res.send(428);
						return;
					}

					// add containment triples if necessary to calculate the correct ETag
					// for containers
					addContainment(req, original, function(err) {
						if (err) {
							console.log(err.stack);
							res.send(500);
							return;
						}

						// calculate the ETag from the text/turtle representation
						asTurtle(original.triples, function(err, turtle) {
							if (err) {
								console.log(err.stack);
								res.send(500);
								return;
							}

							var eTag = getETag(turtle);
							if (ifMatch !== eTag) {
								res.send(412);
								return;
							}

							if (modifiesContainment(original, triples)) {
								res.send(409);
								return;
							}

							// we don't support changing from RDFSource to container or back
							// use the original interaction model
							db.put(req.fullURL, null, original.interactionModel, triples, function(err) {
								if (err) {
									console.log(err.stack);
									res.send(500);
									return;
								}

								res.send(original ? 204 : 201)
							});
						});
					});
				} else {
					// create
					db.put(req.fullURL, null, interactionModel, triples, function(err) {
						if (err) {
							console.log(err.stack);
							res.send(500);
							return;
						}

						res.send(original ? 204 : 201)
					});
				}
			});
		});
	});

	resource.post(function(req, res, next) {
		console.log('POST ' + req.path);
		if (!req.is('text/turtle')) {
			res.send(415);
			return;
		}

		db.isContainer(req.fullURL, function(err, result) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			if (!result) {
				res.send(409);
				return;
			}

			assignURI(req.fullURL, req.get('Slug'), function(err, loc) {
				if (err) {
					console.log(err.stack);
					res.send(500);
					return;
				}

				parse(req, loc, function(err, triples, interactionModel) {
					if (err) {
						// allow the URI to be used again
						db.releaseURI(loc);
						res.send(400);
						return;
					}

					addHeaders(res, interactionModel);

					db.put(loc, req.fullURL, interactionModel, triples, function(err) {
						if (err) {
							console.log(err.stack);
							res.send(500);
							return;
						}

						res.location(loc).send(201);
					});
				});
			});
		});
	});

	resource.delete(function(req, res, next) {
		console.log('DELETE: ' + req.path);
		db.remove(req.fullURL, function(err, result) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			res.send(result ? 204 : 404);
		});
	});

	resource.options(function(req, res, next) {
		db.get(req.fullURL, function(err, document) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			if (document.deleted) {
				res.send(410);
				return;
			}

			if (!document.triples) {
				res.send(404);
				return;
			}

			addHeaders(res, document.interactionModel);
			res.send(200);
		});
	});

	function parse(req, resourceURI, callback) {
		var parser = N3.Parser();
		var triples = [];
		var interactionModel = ldp.RDFSource;
		parser.parse(req.rawBody, function(err, triple) {
			if (err) {
				callback(err);
				return;
			}

			if (triple) {
				// resolve the null relative URI
				if (triple.subject === '') {
					triple.subject = resourceURI;

				}

				// if this triple is <> rdf:type ldp:BasicContainer RDF type,
				// set the interaction model as BasicContainer
				if (triple.subject === resourceURI
					&& triple.predicate === rdf.type
					&& triple.object === ldp.BasicContainer) {
						interactionModel = ldp.BasicContainer;
				}

				triples.push(triple);
				return;
			}

			callback(null, triples, interactionModel);
		});
	}

	function asTurtle(triples, callback) {
		var writer = N3.Writer();
		writer.addTriples(triples);
		writer.end(callback);
	}

	function getETag(turtle) {
		return 'W/"' + crypto.createHash('md5').update(turtle).digest('hex') + '"';
	}

	function addHeaders(res, interactionModel) {
		res.links({ type: ldp.RDFSource });
		var allow = 'GET,HEAD,PUT,DELETE,OPTIONS';
		if (interactionModel === ldp.BasicContainer) {
			res.links({
				type: ldp.BasicContainer
			});

			allow += ',POST';
			res.set('Accept-Post', media.turtle);
		}

		res.set('Allow', allow);
	}

	// insert containment triples if necessary
	function addContainment(req, document, callback) {
		if (document.interactionModel === ldp.BasicContainer) {
			db.getContainment(req.fullURL, function(err, containment) {
				if (containment) {
					containment.forEach(function(resource) {
						document.triples.push({
							subject: req.fullURL,
							predicate: ldp.contains,
							object: resource
						});
					});
				}
				callback(err);
			});
		} else {
			callback();
		}
	}

	function addPath(uri, path) {
		uri = uri.split("?")[0].split("#")[0];
	    if (uri.substr(-1) !== '/') {
			uri += '/';
		}

		// remove special characters from the string (e.g., '/', '..', '?')
		var lastSegment = path.replace(/[^\w\s\-_]/gi, '');
		return uri + encodeURIComponent(lastSegment);
	}

	function uniqueURI(container, callback) {
		var candidate = addPath(container, 'res' + Date.now());
		db.reserveURI(candidate, function(err) {
			callback(err, candidate);
		});
	}

	function assignURI(container, slug, callback) {
		if (slug) {
			var candidate = addPath(container, slug);
			db.reserveURI(candidate, function(err) {
				if (err) {
					uniqueURI(container, callback);
				} else {
					callback(null, candidate);
				}
			});
		} else {
			uniqueURI(container, callback);
		}
	}

	function modifiesContainment(originalDocument, newTriples) {
		if (originalDocument.interactionModel !== ldp.BasicContainer) {
			return false;
		}

		var originalTotal = 0, newTotal = 0, originalContainment = {};
		originalDocument.triples.forEach(function(triple) {
			if (triple.subject === originalDocument.name && triple.predicate === ldp.contains) {
				originalContainment[triple.object] = 1;
				originalTotal++;
			}
		});

		newTriples.forEach(function(triple) {
			if (triple.subject === originalDocument.name && triple.predicate === ldp.contains) {
				if (!originalContainment[triple.object]) {
					return true;
				}
				newTotal++;
			}
		});

		return originalTotal !== newTotal;
	}
};
<commit_msg>create root container on startup if it doesn't exist<commit_after>module.exports = function(app, db, env) {
	var url = require('url');
	var ldp = require('./vocab/ldp.js');			// LDP vocabulary
	var rdf = require('./vocab/rdf.js');			// RDF vocabulary
	var media = require('./media.js');				// media types
	var N3 = require('n3');
	var crypto = require('crypto');					// for MD5 (ETags)

	// create root container if it doesn't exist
	db.get(env.ldpBase, function(err, document) {
		if (err) {
			console.log(err.stack);
			return;
		}

		if (!document) {
			createRootContainer();
		}
	});

	// route any requests matching /r/*
	var resource = app.route(env.context + '*');
	resource.all(function(req, res, next) {
		// all responses should have Link: <ldp:Resource> rel=type
		res.links({
			type: ldp.Resource
		});
		next();
	});

	function get(req, res, includeBody) {
		db.get(req.fullURL, function(err, document) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			if (!document) {
				res.send(404);
				return;
			}

			if (document.deleted) {
				res.send(410);
				return;
			}

			if (!req.accepts(media.turtle)) {
				res.send(406);
				return;
			}

			addHeaders(res, document.interactionModel);
			addContainment(req, document, function(err) {
				if (err) {
					console.log(err.stack);
					res.send(500);
					return;
				}

				asTurtle(document.triples, function(err, turtle) {
					if (err) {
						res.send(500);
					} else {
						var eTag = getETag(turtle);
						if (req.get('If-None-Match') === eTag) {
							res.send(304);
							return;
						}

						res.writeHead(200, { 'ETag': eTag, 'Content-Type': media.turtle });
						if (includeBody) {
							res.end(new Buffer(turtle), 'utf-8');
						} else {
							res.end();
						}
					}
				});
			});
		});
	}

	resource.get(function(req, res, next) {
		console.log('GET ' + req.path);
		get(req, res, true);
	});

	resource.head(function(req, res, next) {
		console.log('HEAD ' + req.path);
		get(req, res, false);
	});

	resource.put(function(req, res, next) {
		console.log('PUT ' + req.path);
		if (!req.is('text/turtle')) {
			res.send(415);
			return;
		}

		parse(req, req.fullURL, function(err, triples, interactionModel) {
			if (err) {
				res.send(400);
				return;
			}

			// get the resource to check if it exists and check its ETag
			db.get(req.fullURL, function(err, original) {
				if (original) {
					if (original.deleted) {
						res.send(410);
						return;
					}

					// update
					var ifMatch = req.get('If-Match');
					if (!ifMatch) {
						res.send(428);
						return;
					}

					// add containment triples if necessary to calculate the correct ETag
					// for containers
					addContainment(req, original, function(err) {
						if (err) {
							console.log(err.stack);
							res.send(500);
							return;
						}

						// calculate the ETag from the text/turtle representation
						asTurtle(original.triples, function(err, turtle) {
							if (err) {
								console.log(err.stack);
								res.send(500);
								return;
							}

							var eTag = getETag(turtle);
							if (ifMatch !== eTag) {
								res.send(412);
								return;
							}

							if (modifiesContainment(original, triples)) {
								res.send(409);
								return;
							}

							// we don't support changing from RDFSource to container or back
							// use the original interaction model
							db.put(req.fullURL, null, original.interactionModel, triples, function(err) {
								if (err) {
									console.log(err.stack);
									res.send(500);
									return;
								}

								res.send(original ? 204 : 201)
							});
						});
					});
				} else {
					// create
					db.put(req.fullURL, null, interactionModel, triples, function(err) {
						if (err) {
							console.log(err.stack);
							res.send(500);
							return;
						}

						res.send(original ? 204 : 201)
					});
				}
			});
		});
	});

	resource.post(function(req, res, next) {
		console.log('POST ' + req.path);
		if (!req.is('text/turtle')) {
			res.send(415);
			return;
		}

		db.isContainer(req.fullURL, function(err, result) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			if (!result) {
				res.send(409);
				return;
			}

			assignURI(req.fullURL, req.get('Slug'), function(err, loc) {
				if (err) {
					console.log(err.stack);
					res.send(500);
					return;
				}

				parse(req, loc, function(err, triples, interactionModel) {
					if (err) {
						// allow the URI to be used again
						db.releaseURI(loc);
						res.send(400);
						return;
					}

					addHeaders(res, interactionModel);

					db.put(loc, req.fullURL, interactionModel, triples, function(err) {
						if (err) {
							console.log(err.stack);
							res.send(500);
							return;
						}

						res.location(loc).send(201);
					});
				});
			});
		});
	});

	resource.delete(function(req, res, next) {
		console.log('DELETE: ' + req.path);
		db.remove(req.fullURL, function(err, result) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			res.send(result ? 204 : 404);
		});
	});

	resource.options(function(req, res, next) {
		db.get(req.fullURL, function(err, document) {
			if (err) {
				console.log(err.stack);
				res.send(500);
				return;
			}

			if (document.deleted) {
				res.send(410);
				return;
			}

			if (!document.triples) {
				res.send(404);
				return;
			}

			addHeaders(res, document.interactionModel);
			res.send(200);
		});
	});

	function createRootContainer() {
		var triples = [{
			subject: env.ldpBase,
			predicate: rdf.type,
			object: ldp.Resource
		}, {
			subject: env.ldpBase,
			predicate: rdf.type,
			object: ldp.RDFSource
		}, {
			subject: env.ldpBase,
			predicate: rdf.type,
			object: ldp.BasicContainer
		}, {
		   	subject: env.ldpBase,
			predicate: 'http://purl.org/dc/terms/title',
    		object: '"LDP.js root container"'
		} ];

		db.put(env.ldpBase, null, ldp.BasicContainer, triples, function(err) {
			if (err) {
				console.log(err.stack);
			}
		});
	}

	function parse(req, resourceURI, callback) {
		var parser = N3.Parser();
		var triples = [];
		var interactionModel = ldp.RDFSource;
		parser.parse(req.rawBody, function(err, triple) {
			if (err) {
				callback(err);
				return;
			}

			if (triple) {
				// resolve the null relative URI
				if (triple.subject === '') {
					triple.subject = resourceURI;

				}

				// if this triple is <> rdf:type ldp:BasicContainer RDF type,
				// set the interaction model as BasicContainer
				if (triple.subject === resourceURI
					&& triple.predicate === rdf.type
					&& triple.object === ldp.BasicContainer) {
						interactionModel = ldp.BasicContainer;
				}

				triples.push(triple);
				return;
			}

			callback(null, triples, interactionModel);
		});
	}

	function asTurtle(triples, callback) {
		var writer = N3.Writer();
		writer.addTriples(triples);
		writer.end(callback);
	}

	function getETag(turtle) {
		return 'W/"' + crypto.createHash('md5').update(turtle).digest('hex') + '"';
	}

	function addHeaders(res, interactionModel) {
		res.links({ type: ldp.RDFSource });
		var allow = 'GET,HEAD,PUT,DELETE,OPTIONS';
		if (interactionModel === ldp.BasicContainer) {
			res.links({
				type: ldp.BasicContainer
			});

			allow += ',POST';
			res.set('Accept-Post', media.turtle);
		}

		res.set('Allow', allow);
	}

	// insert containment triples if necessary
	function addContainment(req, document, callback) {
		if (document.interactionModel === ldp.BasicContainer) {
			db.getContainment(req.fullURL, function(err, containment) {
				if (containment) {
					containment.forEach(function(resource) {
						document.triples.push({
							subject: req.fullURL,
							predicate: ldp.contains,
							object: resource
						});
					});
				}
				callback(err);
			});
		} else {
			callback();
		}
	}

	function addPath(uri, path) {
		uri = uri.split("?")[0].split("#")[0];
	    if (uri.substr(-1) !== '/') {
			uri += '/';
		}

		// remove special characters from the string (e.g., '/', '..', '?')
		var lastSegment = path.replace(/[^\w\s\-_]/gi, '');
		return uri + encodeURIComponent(lastSegment);
	}

	function uniqueURI(container, callback) {
		var candidate = addPath(container, 'res' + Date.now());
		db.reserveURI(candidate, function(err) {
			callback(err, candidate);
		});
	}

	function assignURI(container, slug, callback) {
		if (slug) {
			var candidate = addPath(container, slug);
			db.reserveURI(candidate, function(err) {
				if (err) {
					uniqueURI(container, callback);
				} else {
					callback(null, candidate);
				}
			});
		} else {
			uniqueURI(container, callback);
		}
	}

	function modifiesContainment(originalDocument, newTriples) {
		if (originalDocument.interactionModel !== ldp.BasicContainer) {
			return false;
		}

		var originalTotal = 0, newTotal = 0, originalContainment = {};
		originalDocument.triples.forEach(function(triple) {
			if (triple.subject === originalDocument.name && triple.predicate === ldp.contains) {
				originalContainment[triple.object] = 1;
				originalTotal++;
			}
		});

		newTriples.forEach(function(triple) {
			if (triple.subject === originalDocument.name && triple.predicate === ldp.contains) {
				if (!originalContainment[triple.object]) {
					return true;
				}
				newTotal++;
			}
		});

		return originalTotal !== newTotal;
	}
};
<|endoftext|>


<commit_before>// Used in chicago_gardens.js
var capitalizeConversion = function capitalizeConversion(str) {
  var lower = str.toLowerCase();
  return lower.replace(/(^| )(\w)/g, function(x) {
    return x.toUpperCase();
  });
};

var downloadCSV = function downloadCSV(csv_data) {
  // Reference: https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side
  downloadLink = document.createElement("a");
  blob = new Blob(["\ufeff", csv_data]);
  url = URL.createObjectURL(blob);
  downloadLink.href = url;
  downloadLink.download = "cuamp_gardens.csv";

  document.body.appendChild(downloadLink);
  downloadLink.click();
  document.body.removeChild(downloadLink);
};

// Used in chicago_gardens_map.js
var makeSelectData = function makeSelectData(array) {
  data_arr = []
  for(var i = 0; i < array.length; i++) {
    data_arr.push({ id: i, text: array[i]})
  }
  return data_arr
};

var convertBoolean =  function convertBoolean(text) {
  if (text == true) {
    return " Yes"
  }
  else if (text == false) {
    return " No"
  }
  else {
  }
};

var modalPop = function modalPop(data) {
    var contact = '
 ' + data.address + '
'
    $('#modal-pop').appendTo('body').modal();
    $('#modal-title, #address-header, #owner-header, #community-header, #production-header, #address-subsection, #owner-subsection, #community-subsection, #production-subsection, #locked-header, #locked-subsection, #commtype-header, #commtype-subsection, #types-header, #types-subsection, #water-header, #water-subsection, #compost-header, #compost-subsection, #structures-header, #structures-subsection, #seasonex-header, #seasonex-subsection, #animal-header, #animal-subsection, #dormant-header, #dormant-subsection, #support-header, #support-subsection, #website-header, #website-subsection, #facebook-header, #facebook-subsection, #fence-header, #fence-subsection, #description-header, #description-subsection, #ward-header, #ward-subsection, #commarea-header, #commarea-subsection, #district-header, #district-subsection, #contact-header, #contact-subsection, #withContact, #withLocation, #withInformation, #withFeatures').empty();
    $('#modal-title').html(data.growing_site_name + "
CUAMP ID: " + data.cuamp_id + "
");
    $('#modal-main').html(contact);
    // Header
    var address_list = data.address
    var description = data.description
    // Location
    var ward_num = data.ward
    var community_area = data.community
    var district_number = data.district_n
    // Contact and people
    var owner_list = data.ownership
    var contact_info = data.public_contact_info
    var website = data.growing_site_website
    var facebook = data.facebook
    var other_support = data.other_support_organization
    // Features
    var water_system = data.water
    var compost = data.compost_system
    var structures = data.structures_and_features
    var animals = data.animals
    var fence = data.is_growing_site_fenced
    var production_list = data.food_producing
    // Information
    var community_list = data.community_garden
    var comm_garden_type = data.if_it_s_a_community_garden_is_it_collective_or_allotment
    var types = data.choose_growing_site_types
    var locked = data.is_growing_site_locked
    var season_extension = data.season_extension_techniques
    var dormant = data.is_growing_site_dormant

    // Find all instances of "yes."
    if (types != "") {
      $("#types-header").append(' Garden Type:');
      $("#types-subsection").append("
" + types + "
");
    }
    if (description != "") {
      $("#description-subsection").append("
" + description + "
");
    }

    // Location
    if ((address_list != null) || (ward_num != null) || (community_area != "") || (district_number != "")) {
        // Add header
        $("#withLocation").append('
Location
');
        // Add data
        if (address_list != null) {
          $("#address-header").append(' Address:');
          $("#address-subsection").append("
" + address_list + "
");
        }
        if (ward_num != null) {
          $("#ward-header").append(' Ward:');
          $("#ward-subsection").append("
" + ward_num + "
")
        }
        if (community_area != "") {
          $("#commarea-header").append(' Community Area:');
          $("#commarea-subsection").append("
" + community_area + "
")
        }
        if (district_number != "") {
          $("#district-header").append(' Cook County District:');
          $("#district-subsection").append("
" + district_number + "
")
        }
    }

    // Contact and people
    if ((contact_info != '') || (website != '') || (facebook != '') || (owner_list != '') || (other_support != '')) {
        // Add header
        $("#withContact").append('
Contact and people
');
        // Add data
        if (contact_info != "") {
          $("#contact-header").append(' Contact Info:');
          $("#contact-subsection").append("
" + contact_info + "
")
        }
        if (website != "") {
          $("#website-header").append('
 Website
")
        }
        if (facebook != "") {
          $("#facebook-header").append('
 Facebook Page
');
        }
        if (owner_list != "") {
            $("#owner-header").append(' Ownership:');
            $("#owner-subsection").append("
" + owner_list + "
");
        }
        if (other_support != "") {
          $("#support-header").append(' Support Organizations:');
          $("#support-subsection").append("
" + other_support + "
")
        }
    }

    // Garden features
    if ((water_system != "" && water_system != null) || (production_list != "" && production_list != null) || (compost != "" && compost != null) || (structures != "" && structures != null) || (animals != "" && animals != null) || (fence != "" && fence != null)) {
        // Add header
        $("#withFeatures").append('
Garden features
');
        // Add data
        if (water_system != "" && water_system != null) {
          $("#water-header").append(' Water System:');
          $("#water-subsection").append("
" + water_system + "
");
        }
        if (production_list != "" && production_list != null) {
          $("#production-header").append(' Food Producing:');
          $("#production-subsection").append("
" + convertBoolean(production_list) + "
");
        }
        if (compost != "" && compost != null) {
          $("#compost-header").append(' Compost Available:');
          $("#compost-subsection").append("
" + convertBoolean(compost) + "
")
        }
        if (structures != "" && structures != null) {
          $("#structures-header").append(' Structures and Features:');
          $("#structures-subsection").append("
" + structures + "
")
        }
        if (animals != "" && animals != null) {
          $("#animal-header").append(' Animals:');
          $("#animal-subsection").append("
" + animals + "
")
        }
        if (fence != "" && fence != null) {
          $("#fence-header").append(' Fenced In:');
          $("#fence-subsection").append("
" + convertBoolean(fence) + "
")
        }
    }

    // Information to know
    if ((community_list != "" && community_list != null) || (comm_garden_type != "") || (locked != "") || (season_extension != "") || (dormant != null))  {
        // Add header
        $("#withInformation").append('
Other information');
        // Add data
        if (community_list != "" && community_list != null) {
          $("#community-header").append(' Community Garden:');
          $("#community-subsection").append("
" + convertBoolean(community_list) + "
");
        }
        if (comm_garden_type != "") {
          $("#commtype-header").append(' Community Garden Type:');
          $("#commtype-subsection").append("
" + comm_garden_type + "
")
        }
        if (locked != null) {
          $("#locked-header").append(' Locked Site:');
          $("#locked-subsection").append("
" + convertBoolean(locked) + "
")
        }
        if (dormant != null) {
          $("#dormant-header").append(' Dormant Site:');
          $("#dormant-subsection").append("
" + convertBoolean(dormant) + "
")
        }
        if (season_extension != "") {
          $("#seasonex-header").append(' Season Extension Techniques:
');
          $("#seasonex-subsection").append("
" + season_extension + "
")
        }
    }
};

var hiddenLink = function hiddenLink() {
    url = window.location.href;
    // Check if the user is trying to access the admin download. If yes, then trigger a download of all data.
    if (url.indexOf('?admin=download') > -1) {
      // Download data for composting
      header_names = ["growing_site_name", "address", "ward", "community"]
      chicagoGardens.buildCSV(header_names);
    }
};<commit_msg>Add truthiness checker in utils<commit_after>// Used in chicago_gardens.js
var capitalizeConversion = function capitalizeConversion(str) {
  var lower = str.toLowerCase();
  return lower.replace(/(^| )(\w)/g, function(x) {
    return x.toUpperCase();
  });
};

var downloadCSV = function downloadCSV(csv_data) {
  // Reference: https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side
  downloadLink = document.createElement("a");
  blob = new Blob(["\ufeff", csv_data]);
  url = URL.createObjectURL(blob);
  downloadLink.href = url;
  downloadLink.download = "cuamp_gardens.csv";

  document.body.appendChild(downloadLink);
  downloadLink.click();
  document.body.removeChild(downloadLink);
};

// Used in chicago_gardens_map.js
var makeSelectData = function makeSelectData(array) {
  data_arr = []
  for(var i = 0; i < array.length; i++) {
    data_arr.push({ id: i, text: array[i]})
  }
  return data_arr
};

var convertBoolean =  function convertBoolean(text) {
  if (text == true) {
    return " Yes"
  }
  else if (text == false) {
    return " No"
  }
  else {
  }
};

var modalPop = function modalPop(data) {
    var contact = '
 ' + data.address + '
'
    $('#modal-pop').appendTo('body').modal();
    $('#modal-title, #address-header, #owner-header, #community-header, #production-header, #address-subsection, #owner-subsection, #community-subsection, #production-subsection, #locked-header, #locked-subsection, #commtype-header, #commtype-subsection, #types-header, #types-subsection, #water-header, #water-subsection, #compost-header, #compost-subsection, #structures-header, #structures-subsection, #seasonex-header, #seasonex-subsection, #animal-header, #animal-subsection, #dormant-header, #dormant-subsection, #support-header, #support-subsection, #website-header, #website-subsection, #facebook-header, #facebook-subsection, #fence-header, #fence-subsection, #description-header, #description-subsection, #ward-header, #ward-subsection, #commarea-header, #commarea-subsection, #district-header, #district-subsection, #contact-header, #contact-subsection, #withContact, #withLocation, #withInformation, #withFeatures').empty();
    $('#modal-title').html(data.growing_site_name + "
CUAMP ID: " + data.cuamp_id + "
");
    $('#modal-main').html(contact);
    // Header
    var address_list = data.address
    var description = data.description
    // Location
    var ward_num = data.ward
    var community_area = data.community
    var district_number = data.district_n
    // Contact and people
    var owner_list = data.ownership
    var contact_info = data.public_contact_info
    var website = data.growing_site_website
    var facebook = data.facebook
    var other_support = data.other_support_organization
    // Features
    var water_system = data.water
    var compost = data.compost_system
    var structures = data.structures_and_features
    var animals = data.animals
    var fence = data.is_growing_site_fenced
    var production_list = data.food_producing
    // Information
    var community_list = data.community_garden
    var comm_garden_type = data.if_it_s_a_community_garden_is_it_collective_or_allotment
    var types = data.choose_growing_site_types
    var locked = data.is_growing_site_locked
    var season_extension = data.season_extension_techniques
    var dormant = data.is_growing_site_dormant

    // Find all instances of "yes."
    if (types != "") {
      $("#types-header").append(' Garden Type:');
      $("#types-subsection").append("
" + types + "
");
    }
    if (description != "") {
      $("#description-subsection").append("
" + description + "
");
    }

    // Location
    if (checkTruthiness(address_list) || checkTruthiness(ward_num) || checkTruthiness(community_area) || checkTruthiness(district_number)) {
        // Add header
        $("#withLocation").append('
Location
');
        // Add data
        if (checkTruthiness(address_list)) {
          $("#address-header").append(' Address:');
          $("#address-subsection").append("
" + address_list + "
");
        }
        if (checkTruthiness(ward_num)) {
          $("#ward-header").append(' Ward:');
          $("#ward-subsection").append("
" + ward_num + "
")
        }
        if (checkTruthiness(community_area)) {
          $("#commarea-header").append(' Community Area:');
          $("#commarea-subsection").append("
" + community_area + "
")
        }
        if (checkTruthiness(district_number)) {
          $("#district-header").append(' Cook County District:');
          $("#district-subsection").append("
" + district_number + "
")
        }
    }

    // Contact and people
    if (checkTruthiness(contact_info) || checkTruthiness(website) || checkTruthiness(facebook) || checkTruthiness(owner_list) || checkTruthiness(other_support)) {
        // Add header
        $("#withContact").append('
Contact and people
');
        // Add data
        if (checkTruthiness(contact_info)) {
          $("#contact-header").append(' Contact Info:');
          $("#contact-subsection").append("
" + contact_info + "
")
        }
        if (checkTruthiness(website)) {
          $("#website-header").append('
 Website
")
        }
        if (checkTruthiness(facebook)) {
          $("#facebook-header").append('
 Facebook Page
');
        }
        if (checkTruthiness(owner_list)) {
            $("#owner-header").append(' Ownership:');
            $("#owner-subsection").append("
" + owner_list + "
");
        }
        if (checkTruthiness(other_support)) {
          $("#support-header").append(' Support Organizations:');
          $("#support-subsection").append("
" + other_support + "
")
        }
    }

    // Garden features
    if (checkTruthiness(water_system) || checkTruthiness(production_list) || checkTruthiness(compost) || checkTruthiness(structures) || checkTruthiness(animals) || checkTruthiness(fence)) {
        // Add header
        $("#withFeatures").append('
Garden features
');
        // Add data
        if (checkTruthiness(water_system)) {
          $("#water-header").append(' Water System:');
          $("#water-subsection").append("
" + water_system + "
");
        }
        if (checkTruthiness(production_list)) {
          $("#production-header").append(' Food Producing:');
          $("#production-subsection").append("
" + convertBoolean(production_list) + "
");
        }
        if (checkTruthiness(compost)) {
          $("#compost-header").append(' Compost Available:');
          $("#compost-subsection").append("
" + convertBoolean(compost) + "
")
        }
        if (checkTruthiness(structures)) {
          $("#structures-header").append(' Structures and Features:');
          $("#structures-subsection").append("
" + structures + "
")
        }
        if (checkTruthiness(animals)) {
          $("#animal-header").append(' Animals:');
          $("#animal-subsection").append("
" + animals + "
")
        }
        if (checkTruthiness(fence)) {
          $("#fence-header").append(' Fenced In:');
          $("#fence-subsection").append("
" + convertBoolean(fence) + "
")
        }
    }

    // Other information
    if (checkTruthiness(community_list) || checkTruthiness(comm_garden_type) || checkTruthiness(locked) || checkTruthiness(season_extension) || checkTruthiness(dormant)) {
        // Add header
        $("#withInformation").append('
Other information');
        // Add data
        if (checkTruthiness(community_list)) {
          $("#community-header").append(' Community Garden:');
          $("#community-subsection").append("
" + convertBoolean(community_list) + "
");
        }
        if (checkTruthiness(comm_garden_type)) {
          $("#commtype-header").append(' Community Garden Type:');
          $("#commtype-subsection").append("
" + comm_garden_type + "
")
        }
        if (checkTruthiness(locked)) {
          $("#locked-header").append(' Locked Site:');
          $("#locked-subsection").append("
" + convertBoolean(locked) + "
")
        }
        if (checkTruthiness(season_extension)) {
          $("#seasonex-header").append(' Season Extension Techniques:
');
          $("#seasonex-subsection").append("
" + season_extension + "
")
        }
        if (checkTruthiness(dormant)) {
          $("#dormant-header").append(' Dormant Site:');
          $("#dormant-subsection").append("
" + convertBoolean(dormant) + "
")
        }
    }
};

var hiddenLink = function hiddenLink() {
    url = window.location.href;
    // Check if the user is trying to access the admin download. If yes, then trigger a download of all data.
    if (url.indexOf('?admin=download') > -1) {
      // Download data for composting
      header_names = ["growing_site_name", "address", "ward", "community"]
      chicagoGardens.buildCSV(header_names);
    }
};

var checkTruthiness = function checkTruthiness(text) {
    if ((text != null) && (text != "")) {
      console.log("true", text)
      return true;
    }
    else {
      console.log(text)
      return false;
    }
};<|endoftext|>


<commit_before>let express  = require('express');
let router = express.Router();
let events   = require('../../models/events');
let notifies = require('../../models/notifies');
let Crypto = require('crypto');
let project = require('../../models/project');

let md5 = function (input) {
  return Crypto.createHash('md5').update(input, 'utf8').digest('hex');
};

/**
 * Server-side receiver for Python's exceptions.
 * It takes followings json params in request:
 *
 * @param req.body.token
 * @param req.body.domain
 * @param req.body.message
 * @param req.body.errorLocation.file
 * @param req.body.errorLocation.line
 * @param req.body.errorLocation.full
 * @param req.body.stack
 * @param req.body.time
 */
let getPythonErrors = function (req, res) {
  let request = req.body,
      location = request.errorLocation.file + ':' + request.errorLocation.line;

  let event = {
    type          : 'python',
    tag           : 'fatal',
    token         : request.token,
    message       : request.message,
    errorLocation : request.errorLocation,
    stack         : request.stack,
    groupHash     : md5(location),
    time          : request.time
  };

  project.getByToken(event.token)
    .then( function (foundProject) {
      if (!foundProject) {
        res.sendStatus(403);
        return;
      }

      return events.add(foundProject._id, event)
        .then(function () {
          return foundProject;
        });
    })
    .then(function (foundProject) {
      if (!foundProject) {
        return;
      }

      notifies.send(foundProject, event);

      res.sendStatus(200);
    })
    .catch( function () {
      res.sendStatus(500);
    });
};

/* GET python errors. */
router.post('/python', getPythonErrors);

module.exports = router;
<commit_msg>Update python.js<commit_after>let express  = require('express');
let router = express.Router();
let events   = require('../../models/events');
let notifies = require('../../models/notifies');
let Crypto = require('crypto');
let project = require('../../models/project');

let md5 = function (input) {
  return Crypto.createHash('md5').update(input, 'utf8').digest('hex');
};

/**
 * Server-side receiver for Python's exceptions.
 * It takes followings json params in request:
 *
 * @param req.body.token
 * @param req.body.domain
 * @param req.body.message
 * @param req.body.errorLocation.file
 * @param req.body.errorLocation.line
 * @param req.body.errorLocation.full
 * @param req.body.stack
 * @param req.body.time
 */
let getPythonErrors = function (req, res) {
  let request = req.body,
      location = request.message + ':' + request.errorLocation.file + ':' + request.errorLocation.line;

  let event = {
    type          : 'python',
    tag           : 'fatal',
    token         : request.token,
    message       : request.message,
    errorLocation : request.errorLocation,
    stack         : request.stack,
    groupHash     : md5(location),
    time          : request.time
  };

  project.getByToken(event.token)
    .then( function (foundProject) {
      if (!foundProject) {
        res.sendStatus(403);
        return;
      }

      return events.add(foundProject._id, event)
        .then(function () {
          return foundProject;
        });
    })
    .then(function (foundProject) {
      if (!foundProject) {
        return;
      }

      notifies.send(foundProject, event);

      res.sendStatus(200);
    })
    .catch( function () {
      res.sendStatus(500);
    });
};

/* GET python errors. */
router.post('/python', getPythonErrors);

module.exports = router;
<|endoftext|>


<commit_before>#!/usr/bin/env node
/**
 * A slightly simple webserver for serving a folder.
 */
// requires
var http = require('http');
var util = require('util');
var path = require('path');
var url = require('url');
var fs = require('fs');

var defaults = {
	ip: null, // listen to all ip's

	// first and last port to try out when starting to listen
	// give up if last < first or if none of the ports are free to use
	port: {
		first: 8080,
		last: 8100
	},
	// default mime types
	mime: {
		types: {
			'.txt': 'text/plain',
			'.js': 'text/javascript',
			'.css': 'text/css',
			'.html': 'text/html',
			'.png': 'image/png',
			'.jpg': 'image/jpg'
		}
	}
}

// TODO Real simple HTML5 documents for Error, 404 and dir listing
var docs = {
	template:'<!DOCTYPE html>\n\
		\n\
		\n\
			<title>{title}</title>\n\
		\n\
		\n\

{title}
\n\
			{content}\n\
		\n\
		',
	notFound: {
		title: 'File not found',
		content: 'This is not the file you are looking for.'
	}
};

// basepath for this one
var docRoot = process.cwd();

// functions
var fillTemplate = function (template, values) {
	var t = template;
	for (v in values) {
		t = swapRecursive(t, '{' + v + '}', values[v]);
	}
	return t;
};

var swapRecursive = function (t, from, to) {
	t = t.replace(from, to);
	if (t.indexOf(from) > -1) {
		t = swapRecursive(t, from, to);
	}
	return t;
};

var request_cb = function (req, res) {

	res.setHeader('Content-Type', defaults.mime.types['.txt']); // default mime!
	res.setHeader('Content-Encoding', 'utf-8');
	res.setHeader('Connection', 'close');

	var requestUrl = url.parse(req.url);
	var requestedDocument = path.join(docRoot, requestUrl.pathname);

	util.log('Connection from client: ' + requestUrl.pathname  + ' (' + req.socket.remoteAddress + ').');

	path.exists(requestedDocument, function(exists) {
		if (!exists) {
			var output = fillTemplate(docs.template, docs.notFound);
			res.setHeader('Content-Length', output.length);
			res.setHeader('Content-Type', defaults.mime.types['.html']);
			res.writeHead(404);
			res.end(output);
		} else {
			fs.stat(requestedDocument, function(err, stats) {
				if (err) { throw err; }
				if (stats.isFile()) {

					var ext = path.extname(path.basename(requestedDocument));
					var mime = defaults.mime.types[ext] ? defaults.mime.types[ext] : defaults.mime.types['.txt'];

					res.setHeader('Content-Type', mime);
					res.setHeader('Content-Length', stats.size);
					res.writeHead(200);

					// create stream and pipe it over closing the res when done
					fs.createReadStream(requestedDocument, {
						encoding : 'utf8'
					}).on('end', function () {
						util.log('Served file: ' + this.path);
						//console.log(util.inspect(this));
					}).on('error', function(ex){
						// TODO
						util.log('Error read stream, ex: ' + ex);
					}).pipe(res);

				} else if (stats.isDirectory()) {
					// TODO pretty print directory
					var msg = '200 - Directory Listing.';
					res.setHeader('Content-Length', msg.length);
					res.writeHead(200);
					res.end(msg);
				} else {
					// this means we no want to serve them people
					var msg = '500 - I no know what do!';
					res.setHeader('Content-Length', msg.length);
					res.writeHead(500);
					res.end(msg);
				}
			});
		}
	});
};

var tryListen = function (serv, port) {
	util.log('Servish, trying to bind: ' + port);
	serv.listen(port, defaults.ip);
};

// TODO
// here we should read .servish from $HOME and extend our defaults

util.log('Servish, serving: ' + docRoot);

if (defaults.port.last < defaults.port.first) {
	util.log('Servish, you might have an error with your config (PORT).');
	process.exit(1);
}

var server = http.createServer(request_cb);
var currentPort = defaults.port.first;
server.on('error', function (e) {
	if (e.code == "EADDRINUSE") { // probably a port problem
		util.log('Servish, port in use. Retrying in 1s.');
		setTimeout(function() {
			// TODO Logic for port boundries
			tryListen(server, ++currentPort);
		}, 1000);
	}
});
tryListen(server, currentPort);

process.on('SIGINT', function () {
	util.log('Got SIGINT, shuting down.');
	server.close();
});

util.log('Servish, up and running (probably)!');
<commit_msg>Moved to simple templates for most scenarios<commit_after>#!/usr/bin/env node
/**
 * A slightly simple webserver for serving a folder.
 */
// requires
var http = require('http');
var util = require('util');
var path = require('path');
var url = require('url');
var fs = require('fs');

var defaults = {
	ip: null, // listen to all ip's

	// first and last port to try out when starting to listen
	// give up if last < first or if none of the ports are free to use
	port: {
		first: 8080,
		last: 8100
	},
	// default mime types
	mime: {
		types: {
			'.txt': 'text/plain',
			'.js': 'text/javascript',
			'.css': 'text/css',
			'.html': 'text/html',
			'.png': 'image/png',
			'.jpg': 'image/jpg'
		}
	},
	// a quite simple HTML5 template
	template:
'<!DOCTYPE html>\n\
\n\
\n\
	<title>{title}</title>\n\
\n\
\n\

{title}
\n\
	{content}\n\
\n\
'
}

// TODO Real simple HTML5 documents for Error, 404 and dir listing
var pageContent = {
	notFound: {
		title: '404 - File not found',
		content: 'This is not the file you are looking for.'
	},
	error: {
		title: '500 - Error',
		content: 'Do not know what to do.'
	},
	directoryListing : {
		title: 'Directory Listing',
		content: 'This should never be shown.'
	}
};

// basepath for this one
var docRoot = process.cwd();

// functions
var fillTemplate = function (template, values) {
	var t = template;
	for (v in values) {
		t = swapRecursive(t, '{' + v + '}', values[v]);
	}
	return t;
};

var swapRecursive = function (t, from, to) {
	t = t.replace(from, to);
	if (t.indexOf(from) > -1) {
		t = swapRecursive(t, from, to);
	}
	return t;
};

var requestCallback = function (req, res) {

	res.setHeader('Content-Encoding', 'utf-8');
	res.setHeader('Connection', 'close');

	var requestUrl = url.parse(req.url);
	var requestedDocument = path.join(docRoot, requestUrl.pathname);

	var remoteAddress = req.socket.remoteAddress;

	util.log('Connection from client: ' + requestUrl.pathname  + ' (' + remoteAddress + ').');

	path.exists(requestedDocument, function(exists) {
		if (!exists) {
			var output = fillTemplate(defaults.template, pageContent.notFound);
			//res.setHeader('Content-Length', output.length);
			//res.setHeader('Content-Type', defaults.mime.types['.html']);
			res.writeHead(404, {
				'Content-Length': output.length,
				'Content-Type': defaults.mime.types['.html']
			});
			res.end(output);
			util.log('Served: 404 (' + remoteAddress + ').');
		} else {
			fs.stat(requestedDocument, function(err, stats) {
				if (err) { throw err; }
				if (stats.isFile()) {

					var ext = path.extname(path.basename(requestedDocument));
					var mime = defaults.mime.types[ext] ? defaults.mime.types[ext] : defaults.mime.types['.txt'];

					res.writeHead(200, {
						'Content-Type': mime,
						'Content-Length': stats.size
					});
					// create stream and pipe it, closes res when done
					fs.createReadStream(requestedDocument, {
						encoding : 'utf8'
					}).on('end', function () {
						util.log('Served: ' + this.path + '(' + remoteAddress + ').');
					}).on('error', function(ex){
						// TODO
						util.log('Error read stream, ex: ' + ex);
					}).pipe(res);

				} else if (stats.isDirectory()) {
					// TODO pretty print directory
					var output = fillTemplate(defaults.template, pageContent.directoryListing);
					//res.setHeader('Content-Length', msg.length);
					res.writeHead(200, {
						'Content-Length': output.length
					});
					res.end(output);
					util.log('Served: Directory Listing (' + remoteAddress + ').');
				} else {
					var output = fillTemplate(defaults.template, pageContent.error);
					res.writeHead(500, {
						'Content-Length': output.length
					});
					res.end(output);
					util.log('We nowt sure what to do (' + remoteAddress + ').');
				}
			});
		}
	});
};

var tryListen = function (serv, port) {
	util.log('Servish, trying to bind: ' + port);
	serv.listen(port, defaults.ip);
};

// TODO
// here we should read .servish from $HOME and extend our defaults

util.log('Servish, serving: ' + docRoot);

if (defaults.port.last < defaults.port.first) {
	util.log('Servish, you might have an error with your config (PORT).');
	process.exit(1);
}

var server = http.createServer(requestCallback);
var currentPort = defaults.port.first;
server.on('error', function (e) {
	if (e.code == "EADDRINUSE") { // probably a port problem
		util.log('Servish, port in use. Retrying in 1s.');
		setTimeout(function() {
			// TODO Logic for port boundries
			tryListen(server, ++currentPort);
		}, 1000);
	}
});
tryListen(server, currentPort);

process.on('SIGINT', function () {
	util.log('Got SIGINT, shuting down.');
	server.close();
});

util.log('Servish, up and running (probably)!');
<|endoftext|>