<commit_before>OpenSpending = "OpenSpending" in window ? OpenSpending : {};

(function ($) {

OpenSpending.Treemap = function (elem, context, state) {
  var self = this;

  var resources = [
                 OpenSpending.scriptRoot + "/widgets/treemap/js/thejit-2.min.js",
                 OpenSpending.scriptRoot + "/widgets/treemap/css/treemap.css"
                 ];

  if ($.browser.msie) {
    resources.push(OpenSpending.scriptRoot + "/widgets/treemap/js/excanvas.js");
  }

  self.context = _.extend({
    click: function(node) {
      if (node.data.link) {
        var link = context.embed ? node.data.link + '?embed=true' : node.data.link;
        document.location.href = link;
      }
    },
    hasClick: function(node) {
      return node.data.link !== undefined;
    },
    createLabel: function(widget, domElement, node) {
      if ((node.data.value/self.total)>0.03) {
        domElement.innerHTML = "

" + OpenSpending.Utils.formatAmountWithCommas(node.data.value,0,self.currency) + "

" + node.name + "

";
      }
    },
    tooltipMessage: function(widget, node) {
      var percentualValue = (node.data.value * 100)/widget.total;
      return node.name + " (" + OpenSpending.Utils.formatAmountWithCommas(obj, 2) + "%)";
    }
  }, context);
  self.state = state;

  this.configure = function(endConfigure) {
    self.$qb.empty();
    var qb = new OpenSpending.Widgets.QueryBuilder(
      self.$qb, self.update, endConfigure, self.context, [
            {
              variable: 'drilldowns',
              label: 'Tiles:',
              type: 'select',
              'default': self.state.drilldowns,
              help: 'Each selected dimension will display as an additional level of tiles for the treemap.'
            },
            {
              variable: 'year',
              label: 'Year:',
              type: 'slider',
              'dimension': 'time',
              'attribute': 'year',
              'default': self.state.year,
              help: 'Filter by year.'
            },
            {
              variable: 'cuts',
              label: 'Filters:',
              type: 'cuts',
              'default': self.state.cuts,
              help: 'Limit the set of data to display.'
            }
          ]
    );
  };

  this.update = function(state) {
    self.state = state;
    self.state.drilldowns = self.state.drilldowns || [self.state.drilldown];
    self.state.cuts = self.state.cuts || {};

    var cuts = [];
    for (var field in self.state.cuts) {
      cuts.push(field + ':' + self.state.cuts[field]);
    }

    if (self.state.year) {
      cuts.push('time.year:' + self.state.year);
    }

    if (typeof self.context.member !== 'undefined' && typeof self.context.dimension !== 'undefined') {
      cuts.push(self.context.dimension + ':' + self.context.member);
    }

    //console.log(self.state);
    if (self.state.drilldowns) {
      self.aggregator = new OpenSpending.Aggregator({
        siteUrl: self.context.siteUrl,
        dataset: self.context.dataset,
        drilldowns: self.state.drilldowns,
        cuts: cuts,
        rootNodeLabel: 'Total',
        callback: function(data) {
          self.setDataFromAggregator(this.dataset, data);
        }
      });
    }
  };

  this.getDownloadURL = function() {
    return self.aggregator.getCSVURL();
  };

  this.serialize = function() {
    return self.state;
  };

  this.init = function () {
    self.$e = elem;
    self.$e.before('

');
    self.$qb = elem.prev();
    self.$e.addClass("treemap-widget");
    self.update(state);
  };

  this.setDataFromAggregator = function (dataset, data) {
    self.currency = data.currency;
    self.setNode(data);
  };

  this.setNode = function (node) {
    var needsColorization = true;
    self.total = node.amount;
    self.data = {children: _.map(node.children, function(item) {
      if (item.color)
        needsColorization = false;
      return {
        children: [],
        id: item.id,
        name: item.label || item.name,
        data: {
            node: item,
            value: item.amount,
            $area: item.amount,
            title: item.label || item.name,
            link: item.html_url,
            name: item.name,
            $color: item.color || '#333333'
          }
        };
    })};

    if (needsColorization) {
      this.autoColorize();
    }
    self.draw();

  };

  this.drilldown = function(tile) {
    if (!tile.data.node.children.length) {
      self.context.click(tile);
    } else {
      self.setNode(tile.data.node);
    }
  };

  this.autoColorize = function() {
    var nodes = self.data.children.length;
    var colors = OpenSpending.Utils.getColorPalette(nodes);
    for (var i = 0; i < nodes; i++) {
      self.data.children[i].data.$color = colors[i];
    }
  };

  this.draw = function () {
    self.$e.empty();
    if (!self.data.children.length) {
      $(self.$e).hide();
      return;
    }
    $(self.$e).show();
    self.tm = new $jit.TM.Squarified({
        injectInto: self.$e.prop('id'),
        levelsToShow: 1,
        titleHeight: 0,
        animate: true,
        transition: $jit.Trans.Expo.easeOut,

        offset: 2,
        Label: {
          type: 'HTML',
          size: 12,
          family: 'Tahoma, Verdana, Arial',
          color: '#DDE7F0'
          },
        Node: {
          color: '#243448',
          CanvasStyles: {
            shadowBlur: 0,
            shadowColor: '#000'
          }
        },
        Events: {
          enable: true,
          onClick: function(node) {
            if(node) {
              self.drilldown(node);
            }
          },
          onRightClick: function() {
            self.tm.out();
          },
          onMouseEnter: function(node, eventInfo) {
            if(node) {
              if (!self.context.hasClick(node)) {
                self.$e.find('#'+node.id).css('cursor', 'default');
              }
              node.setCanvasStyle('shadowBlur', 8);
              node.orig_color = node.getData('color');
              node.setData('color', '#A3B3C7');
              self.tm.fx.plotNode(node, self.tm.canvas);
            }
          },
          onMouseLeave: function(node) {
            if(node) {
              node.removeData('color');
              node.removeCanvasStyle('shadowBlur');
              node.setData('color', node.orig_color);
              self.tm.plot();
            }
          }
        },
        duration: 1000,
        Tips: {
          enable: true,
          type: 'Native',
          offsetX: 20,
          offsetY: 20,
          onShow: function(tip, node, isLeaf, domElement) {
            var html = '
' +
                self.context.tooltipMessage(self, node) +
                '

';
            var data = node.data;
            tip.innerHTML = html;
          }
        },
        //Implement this method for retrieving a requested
        //subtree that has as root a node with id = nodeId,
        //and level as depth. This method could also make a server-side
        //call for the requested subtree. When completed, the onComplete
        //callback method should be called.
        request: function(nodeId, level, onComplete){
          // var tree = eval('(' + json + ')');
          var tree = json;
          var subtree = $jit.json.getSubtree(tree, nodeId);
          $jit.json.prune(subtree, 1);
          onComplete.onComplete(nodeId, subtree);
        },
        //Add the name of the node in the corresponding label
        //This method is called once, on label creation and only for DOM labels.
        onCreateLabel: function(domElement, node){
          self.context.createLabel(self, domElement, node);
        }
    });
    self.tm.loadJSON(this.data);
    self.tm.refresh();
  };

  // The rest of this function is suitable for copypasta into other
  // plugins: load all scripts we need, and return a promise object
  // that will fire when the class is ready
  var dfd = $.Deferred();
  dfd.done(function(that) {that.init();});

  if (!window.treemapWidgetLoaded) {
    yepnope({
      load: resources,
      complete: function() {
        window.treemapWidgetLoaded = true;
        dfd.resolve(self);
      }
    });
  } else {
    dfd.resolve(self);
  }

  return dfd.promise();
};

})(jQuery);

<commit_msg>Fixes typo in last commit<commit_after>OpenSpending = "OpenSpending" in window ? OpenSpending : {};

(function ($) {

OpenSpending.Treemap = function (elem, context, state) {
  var self = this;

  var resources = [
                 OpenSpending.scriptRoot + "/widgets/treemap/js/thejit-2.min.js",
                 OpenSpending.scriptRoot + "/widgets/treemap/css/treemap.css"
                 ];

  if ($.browser.msie) {
    resources.push(OpenSpending.scriptRoot + "/widgets/treemap/js/excanvas.js");
  }

  self.context = _.extend({
    click: function(node) {
      if (node.data.link) {
        var link = context.embed ? node.data.link + '?embed=true' : node.data.link;
        document.location.href = link;
      }
    },
    hasClick: function(node) {
      return node.data.link !== undefined;
    },
    createLabel: function(widget, domElement, node) {
      if ((node.data.value/self.total)>0.03) {
        domElement.innerHTML = "

" + OpenSpending.Utils.formatAmountWithCommas(node.data.value,0,self.currency) + "

" + node.name + "

";
      }
    },
    tooltipMessage: function(widget, node) {
      var percentualValue = (node.data.value * 100)/widget.total;
      return node.name + " (" + OpenSpending.Utils.formatAmountWithCommas(percentualValue, 2) + "%)";
    }
  }, context);
  self.state = state;

  this.configure = function(endConfigure) {
    self.$qb.empty();
    var qb = new OpenSpending.Widgets.QueryBuilder(
      self.$qb, self.update, endConfigure, self.context, [
            {
              variable: 'drilldowns',
              label: 'Tiles:',
              type: 'select',
              'default': self.state.drilldowns,
              help: 'Each selected dimension will display as an additional level of tiles for the treemap.'
            },
            {
              variable: 'year',
              label: 'Year:',
              type: 'slider',
              'dimension': 'time',
              'attribute': 'year',
              'default': self.state.year,
              help: 'Filter by year.'
            },
            {
              variable: 'cuts',
              label: 'Filters:',
              type: 'cuts',
              'default': self.state.cuts,
              help: 'Limit the set of data to display.'
            }
          ]
    );
  };

  this.update = function(state) {
    self.state = state;
    self.state.drilldowns = self.state.drilldowns || [self.state.drilldown];
    self.state.cuts = self.state.cuts || {};

    var cuts = [];
    for (var field in self.state.cuts) {
      cuts.push(field + ':' + self.state.cuts[field]);
    }

    if (self.state.year) {
      cuts.push('time.year:' + self.state.year);
    }

    if (typeof self.context.member !== 'undefined' && typeof self.context.dimension !== 'undefined') {
      cuts.push(self.context.dimension + ':' + self.context.member);
    }

    //console.log(self.state);
    if (self.state.drilldowns) {
      self.aggregator = new OpenSpending.Aggregator({
        siteUrl: self.context.siteUrl,
        dataset: self.context.dataset,
        drilldowns: self.state.drilldowns,
        cuts: cuts,
        rootNodeLabel: 'Total',
        callback: function(data) {
          self.setDataFromAggregator(this.dataset, data);
        }
      });
    }
  };

  this.getDownloadURL = function() {
    return self.aggregator.getCSVURL();
  };

  this.serialize = function() {
    return self.state;
  };

  this.init = function () {
    self.$e = elem;
    self.$e.before('

');
    self.$qb = elem.prev();
    self.$e.addClass("treemap-widget");
    self.update(state);
  };

  this.setDataFromAggregator = function (dataset, data) {
    self.currency = data.currency;
    self.setNode(data);
  };

  this.setNode = function (node) {
    var needsColorization = true;
    self.total = node.amount;
    self.data = {children: _.map(node.children, function(item) {
      if (item.color)
        needsColorization = false;
      return {
        children: [],
        id: item.id,
        name: item.label || item.name,
        data: {
            node: item,
            value: item.amount,
            $area: item.amount,
            title: item.label || item.name,
            link: item.html_url,
            name: item.name,
            $color: item.color || '#333333'
          }
        };
    })};

    if (needsColorization) {
      this.autoColorize();
    }
    self.draw();

  };

  this.drilldown = function(tile) {
    if (!tile.data.node.children.length) {
      self.context.click(tile);
    } else {
      self.setNode(tile.data.node);
    }
  };

  this.autoColorize = function() {
    var nodes = self.data.children.length;
    var colors = OpenSpending.Utils.getColorPalette(nodes);
    for (var i = 0; i < nodes; i++) {
      self.data.children[i].data.$color = colors[i];
    }
  };

  this.draw = function () {
    self.$e.empty();
    if (!self.data.children.length) {
      $(self.$e).hide();
      return;
    }
    $(self.$e).show();
    self.tm = new $jit.TM.Squarified({
        injectInto: self.$e.prop('id'),
        levelsToShow: 1,
        titleHeight: 0,
        animate: true,
        transition: $jit.Trans.Expo.easeOut,

        offset: 2,
        Label: {
          type: 'HTML',
          size: 12,
          family: 'Tahoma, Verdana, Arial',
          color: '#DDE7F0'
          },
        Node: {
          color: '#243448',
          CanvasStyles: {
            shadowBlur: 0,
            shadowColor: '#000'
          }
        },
        Events: {
          enable: true,
          onClick: function(node) {
            if(node) {
              self.drilldown(node);
            }
          },
          onRightClick: function() {
            self.tm.out();
          },
          onMouseEnter: function(node, eventInfo) {
            if(node) {
              if (!self.context.hasClick(node)) {
                self.$e.find('#'+node.id).css('cursor', 'default');
              }
              node.setCanvasStyle('shadowBlur', 8);
              node.orig_color = node.getData('color');
              node.setData('color', '#A3B3C7');
              self.tm.fx.plotNode(node, self.tm.canvas);
            }
          },
          onMouseLeave: function(node) {
            if(node) {
              node.removeData('color');
              node.removeCanvasStyle('shadowBlur');
              node.setData('color', node.orig_color);
              self.tm.plot();
            }
          }
        },
        duration: 1000,
        Tips: {
          enable: true,
          type: 'Native',
          offsetX: 20,
          offsetY: 20,
          onShow: function(tip, node, isLeaf, domElement) {
            var html = '
' +
                self.context.tooltipMessage(self, node) +
                '

';
            var data = node.data;
            tip.innerHTML = html;
          }
        },
        //Implement this method for retrieving a requested
        //subtree that has as root a node with id = nodeId,
        //and level as depth. This method could also make a server-side
        //call for the requested subtree. When completed, the onComplete
        //callback method should be called.
        request: function(nodeId, level, onComplete){
          // var tree = eval('(' + json + ')');
          var tree = json;
          var subtree = $jit.json.getSubtree(tree, nodeId);
          $jit.json.prune(subtree, 1);
          onComplete.onComplete(nodeId, subtree);
        },
        //Add the name of the node in the corresponding label
        //This method is called once, on label creation and only for DOM labels.
        onCreateLabel: function(domElement, node){
          self.context.createLabel(self, domElement, node);
        }
    });
    self.tm.loadJSON(this.data);
    self.tm.refresh();
  };

  // The rest of this function is suitable for copypasta into other
  // plugins: load all scripts we need, and return a promise object
  // that will fire when the class is ready
  var dfd = $.Deferred();
  dfd.done(function(that) {that.init();});

  if (!window.treemapWidgetLoaded) {
    yepnope({
      load: resources,
      complete: function() {
        window.treemapWidgetLoaded = true;
        dfd.resolve(self);
      }
    });
  } else {
    dfd.resolve(self);
  }

  return dfd.promise();
};

})(jQuery);

<|endoftext|>


<commit_before>/*************************************************************************/
/*  library_godot_os.js                                                  */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

const IDHandler = {
	$IDHandler: {
		_last_id: 0,
		_references: {},

		get: function (p_id) {
			return IDHandler._references[p_id];
		},

		add: function (p_data) {
			const id = ++IDHandler._last_id;
			IDHandler._references[id] = p_data;
			return id;
		},

		remove: function (p_id) {
			delete IDHandler._references[p_id];
		},
	},
};

autoAddDeps(IDHandler, '$IDHandler');
mergeInto(LibraryManager.library, IDHandler);

const GodotConfig = {
	$GodotConfig__postset: 'Module["initConfig"] = GodotConfig.init_config;',
	$GodotConfig__deps: ['$GodotRuntime'],
	$GodotConfig: {
		canvas: null,
		locale: 'en',
		resize_on_start: false,
		on_execute: null,

		init_config: function (p_opts) {
			GodotConfig.resize_on_start = !!p_opts['resizeCanvasOnStart'];
			GodotConfig.canvas = p_opts['canvas'];
			GodotConfig.locale = p_opts['locale'] || GodotConfig.locale;
			GodotConfig.on_execute = p_opts['onExecute'];
			// This is called by emscripten, even if undocumented.
			Module['onExit'] = p_opts['onExit']; // eslint-disable-line no-undef
		},

		locate_file: function (file) {
			return Module['locateFile'](file); // eslint-disable-line no-undef
		},
	},

	godot_js_config_canvas_id_get: function (p_ptr, p_ptr_max) {
		GodotRuntime.stringToHeap(`#${GodotConfig.canvas.id}`, p_ptr, p_ptr_max);
	},

	godot_js_config_locale_get: function (p_ptr, p_ptr_max) {
		GodotRuntime.stringToHeap(GodotConfig.locale, p_ptr, p_ptr_max);
	},

	godot_js_config_is_resize_on_start: function () {
		return GodotConfig.resize_on_start ? 1 : 0;
	},
};

autoAddDeps(GodotConfig, '$GodotConfig');
mergeInto(LibraryManager.library, GodotConfig);

const GodotFS = {
	$GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'],
	$GodotFS__postset: [
		'Module["initFS"] = GodotFS.init;',
		'Module["deinitFS"] = GodotFS.deinit;',
		'Module["copyToFS"] = GodotFS.copy_to_fs;',
	].join(''),
	$GodotFS: {
		_idbfs: false,
		_syncing: false,
		_mount_points: [],

		is_persistent: function () {
			return GodotFS._idbfs ? 1 : 0;
		},

		// Initialize godot file system, setting up persistent paths.
		// Returns a promise that resolves when the FS is ready.
		// We keep track of mount_points, so that we can properly close the IDBFS
		// since emscripten is not doing it by itself. (emscripten GH#12516).
		init: function (persistentPaths) {
			GodotFS._idbfs = false;
			if (!Array.isArray(persistentPaths)) {
				return Promise.reject(new Error('Persistent paths must be an array'));
			}
			if (!persistentPaths.length) {
				return Promise.resolve();
			}
			GodotFS._mount_points = persistentPaths.slice();

			function createRecursive(dir) {
				try {
					FS.stat(dir);
				} catch (e) {
					if (e.errno !== ERRNO_CODES.ENOENT) {
						throw e;
					}
					FS.mkdirTree(dir);
				}
			}

			GodotFS._mount_points.forEach(function (path) {
				createRecursive(path);
				FS.mount(IDBFS, {}, path);
			});
			return new Promise(function (resolve, reject) {
				FS.syncfs(true, function (err) {
					if (err) {
						GodotFS._mount_points = [];
						GodotFS._idbfs = false;
						GodotRuntime.print(`IndexedDB not available: ${err.message}`);
					} else {
						GodotFS._idbfs = true;
					}
					resolve(err);
				});
			});
		},

		// Deinit godot file system, making sure to unmount file systems, and close IDBFS(s).
		deinit: function () {
			GodotFS._mount_points.forEach(function (path) {
				try {
					FS.unmount(path);
				} catch (e) {
					GodotRuntime.print('Already unmounted', e);
				}
				if (GodotFS._idbfs && IDBFS.dbs[path]) {
					IDBFS.dbs[path].close();
					delete IDBFS.dbs[path];
				}
			});
			GodotFS._mount_points = [];
			GodotFS._idbfs = false;
			GodotFS._syncing = false;
		},

		sync: function () {
			if (GodotFS._syncing) {
				GodotRuntime.error('Already syncing!');
				return Promise.resolve();
			}
			GodotFS._syncing = true;
			return new Promise(function (resolve, reject) {
				FS.syncfs(false, function (error) {
					if (error) {
						GodotRuntime.error(`Failed to save IDB file system: ${error.message}`);
					}
					GodotFS._syncing = false;
					resolve(error);
				});
			});
		},

		// Copies a buffer to the internal file system. Creating directories recursively.
		copy_to_fs: function (path, buffer) {
			const idx = path.lastIndexOf('/');
			let dir = '/';
			if (idx > 0) {
				dir = path.slice(0, idx);
			}
			try {
				FS.stat(dir);
			} catch (e) {
				if (e.errno !== ERRNO_CODES.ENOENT) {
					throw e;
				}
				FS.mkdirTree(dir);
			}
			FS.writeFile(path, new Uint8Array(buffer), { 'flags': 'wx+' });
		},
	},
};
mergeInto(LibraryManager.library, GodotFS);

const GodotOS = {
	$GodotOS__deps: ['$GodotFS', '$GodotRuntime'],
	$GodotOS__postset: [
		'Module["request_quit"] = function() { GodotOS.request_quit() };',
		'GodotOS._fs_sync_promise = Promise.resolve();',
	].join(''),
	$GodotOS: {
		request_quit: function () {},
		_async_cbs: [],
		_fs_sync_promise: null,

		atexit: function (p_promise_cb) {
			GodotOS._async_cbs.push(p_promise_cb);
		},

		finish_async: function (callback) {
			GodotOS._fs_sync_promise.then(function (err) {
				const promises = [];
				GodotOS._async_cbs.forEach(function (cb) {
					promises.push(new Promise(cb));
				});
				return Promise.all(promises);
			}).then(function () {
				return GodotFS.sync(); // Final FS sync.
			}).then(function (err) {
				// Always deferred.
				setTimeout(function () {
					callback();
				}, 0);
			});
		},
	},

	godot_js_os_finish_async: function (p_callback) {
		const func = GodotRuntime.get_func(p_callback);
		GodotOS.finish_async(func);
	},

	godot_js_os_request_quit_cb: function (p_callback) {
		GodotOS.request_quit = GodotRuntime.get_func(p_callback);
	},

	godot_js_os_fs_is_persistent: function () {
		return GodotFS.is_persistent();
	},

	godot_js_os_fs_sync: function (callback) {
		const func = GodotRuntime.get_func(callback);
		GodotOS._fs_sync_promise = GodotFS.sync();
		GodotOS._fs_sync_promise.then(function (err) {
			func();
		});
	},

	godot_js_os_execute: function (p_json) {
		const json_args = GodotRuntime.parseString(p_json);
		const args = JSON.parse(json_args);
		if (GodotConfig.on_execute) {
			GodotConfig.on_execute(args);
			return 0;
		}
		return 1;
	},

	godot_js_os_shell_open: function (p_uri) {
		window.open(GodotRuntime.parseString(p_uri), '_blank');
	},
};

autoAddDeps(GodotOS, '$GodotOS');
mergeInto(LibraryManager.library, GodotOS);
<commit_msg>[HTML5] Remove file flags from writeFile in setup.<commit_after>/*************************************************************************/
/*  library_godot_os.js                                                  */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

const IDHandler = {
	$IDHandler: {
		_last_id: 0,
		_references: {},

		get: function (p_id) {
			return IDHandler._references[p_id];
		},

		add: function (p_data) {
			const id = ++IDHandler._last_id;
			IDHandler._references[id] = p_data;
			return id;
		},

		remove: function (p_id) {
			delete IDHandler._references[p_id];
		},
	},
};

autoAddDeps(IDHandler, '$IDHandler');
mergeInto(LibraryManager.library, IDHandler);

const GodotConfig = {
	$GodotConfig__postset: 'Module["initConfig"] = GodotConfig.init_config;',
	$GodotConfig__deps: ['$GodotRuntime'],
	$GodotConfig: {
		canvas: null,
		locale: 'en',
		resize_on_start: false,
		on_execute: null,

		init_config: function (p_opts) {
			GodotConfig.resize_on_start = !!p_opts['resizeCanvasOnStart'];
			GodotConfig.canvas = p_opts['canvas'];
			GodotConfig.locale = p_opts['locale'] || GodotConfig.locale;
			GodotConfig.on_execute = p_opts['onExecute'];
			// This is called by emscripten, even if undocumented.
			Module['onExit'] = p_opts['onExit']; // eslint-disable-line no-undef
		},

		locate_file: function (file) {
			return Module['locateFile'](file); // eslint-disable-line no-undef
		},
	},

	godot_js_config_canvas_id_get: function (p_ptr, p_ptr_max) {
		GodotRuntime.stringToHeap(`#${GodotConfig.canvas.id}`, p_ptr, p_ptr_max);
	},

	godot_js_config_locale_get: function (p_ptr, p_ptr_max) {
		GodotRuntime.stringToHeap(GodotConfig.locale, p_ptr, p_ptr_max);
	},

	godot_js_config_is_resize_on_start: function () {
		return GodotConfig.resize_on_start ? 1 : 0;
	},
};

autoAddDeps(GodotConfig, '$GodotConfig');
mergeInto(LibraryManager.library, GodotConfig);

const GodotFS = {
	$GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'],
	$GodotFS__postset: [
		'Module["initFS"] = GodotFS.init;',
		'Module["deinitFS"] = GodotFS.deinit;',
		'Module["copyToFS"] = GodotFS.copy_to_fs;',
	].join(''),
	$GodotFS: {
		_idbfs: false,
		_syncing: false,
		_mount_points: [],

		is_persistent: function () {
			return GodotFS._idbfs ? 1 : 0;
		},

		// Initialize godot file system, setting up persistent paths.
		// Returns a promise that resolves when the FS is ready.
		// We keep track of mount_points, so that we can properly close the IDBFS
		// since emscripten is not doing it by itself. (emscripten GH#12516).
		init: function (persistentPaths) {
			GodotFS._idbfs = false;
			if (!Array.isArray(persistentPaths)) {
				return Promise.reject(new Error('Persistent paths must be an array'));
			}
			if (!persistentPaths.length) {
				return Promise.resolve();
			}
			GodotFS._mount_points = persistentPaths.slice();

			function createRecursive(dir) {
				try {
					FS.stat(dir);
				} catch (e) {
					if (e.errno !== ERRNO_CODES.ENOENT) {
						throw e;
					}
					FS.mkdirTree(dir);
				}
			}

			GodotFS._mount_points.forEach(function (path) {
				createRecursive(path);
				FS.mount(IDBFS, {}, path);
			});
			return new Promise(function (resolve, reject) {
				FS.syncfs(true, function (err) {
					if (err) {
						GodotFS._mount_points = [];
						GodotFS._idbfs = false;
						GodotRuntime.print(`IndexedDB not available: ${err.message}`);
					} else {
						GodotFS._idbfs = true;
					}
					resolve(err);
				});
			});
		},

		// Deinit godot file system, making sure to unmount file systems, and close IDBFS(s).
		deinit: function () {
			GodotFS._mount_points.forEach(function (path) {
				try {
					FS.unmount(path);
				} catch (e) {
					GodotRuntime.print('Already unmounted', e);
				}
				if (GodotFS._idbfs && IDBFS.dbs[path]) {
					IDBFS.dbs[path].close();
					delete IDBFS.dbs[path];
				}
			});
			GodotFS._mount_points = [];
			GodotFS._idbfs = false;
			GodotFS._syncing = false;
		},

		sync: function () {
			if (GodotFS._syncing) {
				GodotRuntime.error('Already syncing!');
				return Promise.resolve();
			}
			GodotFS._syncing = true;
			return new Promise(function (resolve, reject) {
				FS.syncfs(false, function (error) {
					if (error) {
						GodotRuntime.error(`Failed to save IDB file system: ${error.message}`);
					}
					GodotFS._syncing = false;
					resolve(error);
				});
			});
		},

		// Copies a buffer to the internal file system. Creating directories recursively.
		copy_to_fs: function (path, buffer) {
			const idx = path.lastIndexOf('/');
			let dir = '/';
			if (idx > 0) {
				dir = path.slice(0, idx);
			}
			try {
				FS.stat(dir);
			} catch (e) {
				if (e.errno !== ERRNO_CODES.ENOENT) {
					throw e;
				}
				FS.mkdirTree(dir);
			}
			FS.writeFile(path, new Uint8Array(buffer));
		},
	},
};
mergeInto(LibraryManager.library, GodotFS);

const GodotOS = {
	$GodotOS__deps: ['$GodotFS', '$GodotRuntime'],
	$GodotOS__postset: [
		'Module["request_quit"] = function() { GodotOS.request_quit() };',
		'GodotOS._fs_sync_promise = Promise.resolve();',
	].join(''),
	$GodotOS: {
		request_quit: function () {},
		_async_cbs: [],
		_fs_sync_promise: null,

		atexit: function (p_promise_cb) {
			GodotOS._async_cbs.push(p_promise_cb);
		},

		finish_async: function (callback) {
			GodotOS._fs_sync_promise.then(function (err) {
				const promises = [];
				GodotOS._async_cbs.forEach(function (cb) {
					promises.push(new Promise(cb));
				});
				return Promise.all(promises);
			}).then(function () {
				return GodotFS.sync(); // Final FS sync.
			}).then(function (err) {
				// Always deferred.
				setTimeout(function () {
					callback();
				}, 0);
			});
		},
	},

	godot_js_os_finish_async: function (p_callback) {
		const func = GodotRuntime.get_func(p_callback);
		GodotOS.finish_async(func);
	},

	godot_js_os_request_quit_cb: function (p_callback) {
		GodotOS.request_quit = GodotRuntime.get_func(p_callback);
	},

	godot_js_os_fs_is_persistent: function () {
		return GodotFS.is_persistent();
	},

	godot_js_os_fs_sync: function (callback) {
		const func = GodotRuntime.get_func(callback);
		GodotOS._fs_sync_promise = GodotFS.sync();
		GodotOS._fs_sync_promise.then(function (err) {
			func();
		});
	},

	godot_js_os_execute: function (p_json) {
		const json_args = GodotRuntime.parseString(p_json);
		const args = JSON.parse(json_args);
		if (GodotConfig.on_execute) {
			GodotConfig.on_execute(args);
			return 0;
		}
		return 1;
	},

	godot_js_os_shell_open: function (p_uri) {
		window.open(GodotRuntime.parseString(p_uri), '_blank');
	},
};

autoAddDeps(GodotOS, '$GodotOS');
mergeInto(LibraryManager.library, GodotOS);
<|endoftext|>


<commit_before>/*

hashban.js is a plugin to streamline the addition of ajax-style page transitions
to a website.

Example:

    var hashban = Hashban({
        contentWrapSelector: '#mycontent'
    });
    hashban.hijack($('#header nav'));
    hashban.bind();

Options/defaults:

    contentWrapSelector: '#content',
    duration: 500,
    transition_out: transition_out,
    transition_in: transition_in,
    loader: $.hashban.loader,
    link_order: [],
    link_filter: null,
    loaderTimeout: 300

*/

var Hashban = (function($) {

    function Hashban(user_options) {
        if (!(this instanceof Hashban)) return new Hashban(user_options);
        var that = this;

        function transition_out(endfade, old_content, data) {
            // Default transition out: fade the old content out, and call
            // end_callback once the transition is done

            old_content.fadeOut(that.options.duration, endfade);
        };

        function transition_in(new_content, old_content, data) {
            // Default transition in: remove the old content (in case it's
            // still there) and fade the new content in.

            old_content.remove();
            new_content.fadeIn(that.options.duration);
        };

        function loader(visible) {
            // this function toggles the "loading" state, based on
            // the parameter. If creating a loader element on the
            // page, it should return this element.

            // TODO uid for loader class?

            var loading = $('.hashban-loader');
            if (!loading.length) {
                loading = $('<span>').addClass('hashban-loader')
                                     .text('Loading').hide();
                $(that.options.contentWrapSelector).append(loading);
            }
            if (visible === true) {
                loading.show();
            }
            else if (visible === false) {
                loading.hide();
            }
            return loading;
        };

        this.CACHE = {};
        this.currentXHR = null;
        this.previous_url = window.location.pathname;
        this.options = $.extend({
            contentWrapSelector: '#content',
            duration: 500,
            transition_out: transition_out,
            transition_in: transition_in,
            content_init: null,
            loader: loader,
            link_order: [],
            loaderTimeout: 300,
            uid: 'Hashban.js'
        }, user_options);

    };

    Hashban.LOAD_EVENT = 'hashban-load';
    Hashban.UNLOAD_EVENT = 'hashban-unload';

    Hashban.prototype.bind = function(){
        var that = this;

        $(window).bind('popstate', function(e) {
            if (e.originalEvent.state &&
                e.originalEvent.state['handler'] === that.options['uid']) {
                that.loadPage(window.location.pathname, true);
                return false;
            }
        });
    };

    Hashban.prototype.hashban = function(links){
        // bind the given links (a jquery collection) to load via ajax

        var that = this;
        links.each(function() {
            var me = $(this),
                url = me.attr('href');

            // TODO uid here? can you bind two Hashbans to one link?

            if (!me.data('hashbanned')) {
                me.click(function() {
                    that.loadPage(url);
                    return false;
                });
                me.data('hashbanned', true);
            }
        });

    };

    Hashban.prototype.hijack = function(el, link_filter) {
        // find suitable links within the given element(s), and hijack them
        // to load via ajax

        var domain = getmatch(window.location.href, /[^\/]+\/\/[^\/]+/, 0),
            links = el.find('a:not([href^="http://"]), ' +
                            'a[href^="' + domain + '"]')
                        .not('[href$=".xml"], [href$=".pdf"], ' +
                             '[href$=".jpg"], [href$=".gif"], ' +
                             '[href$=".png"], [href^="#"]');

        if (link_filter) {
            links = links.filter(link_filter);
        }

        this.hashban(links);

        return el;
    };

    Hashban.prototype.loadPage = function (url, state) {
        // Load the specified url. If state is passed, it is assumed to be the
        // state dictionary from the popstate event, (i.e. back button) and the
        // pageload is handled accordingly. Otherwise, it is assumed the
        // pageLoad was initiated by the user clicking a link.

        var that = this,
            contentWrap = $(this.options.contentWrapSelector),
            html,
            error,
            loaderTimer,
            faded = false,
            completed = false,
            transition_data = {
                direction: get_direction(this.previous_url, url,
                                         this.options.link_order),
                from: this.previous_url,
                to: url,
                state: state
            };

        if (this.previous_url !== url) {

            // save scroll position in current state; also means the transition
            // will work if the user navigates to the originally loaded page
            // via the back button
            if (!state) {
                window.history.replaceState(that.buildState({
                    scrollTop: $(window).scrollTop()
                }), null, window.location);
            }

            // Order of events
            // 1. start loading
            // 2. transition out old content
            // 3. show spinner
            // 4. once load and transition out are both done, transition in

            function fadein() {
                var contentBody = Hashban.getBody(html),
                    bodyClass = contentBody.attr('class'),
                    contentEl = contentBody.find(
                                    that.options.contentWrapSelector),
                    title = getmatch(html, /<title>([\s\S]*?)<\/title>/, 1);

                if (contentEl.length) {
                    if (!state) {
                        // assume a link was clicked if no state present
                        history.pushState(that.buildState(), null, url);
                    }
                    document.title = $('<div>').html(title).text();

                    $('body').attr('class', bodyClass);

                    clearTimeout(loaderTimer);
                    that.options.loader(false);

                    var new_content = contentEl.children(),
                        old_content = contentWrap.children()
                                                 .not(that.options.loader());

                    // trigger unload event here so that it won't effect any
                    // new content
                    // TODO uid here?
                    $(window).trigger(Hashban.UNLOAD_EVENT);

                    new_content.appendTo(contentWrap).hide();

                    transition_data.contentBody = contentBody;
                    that.options.transition_in(new_content, old_content,
                                               transition_data);

                    if (typeof that.options.content_init === 'function') {
                        that.options.content_init(new_content);
                    }

                    // if the load was triggered by popstate, eg. the back
                    // button and not a clicked link, restore scroll position
                    if (state && state.scrollTop) {
                        $(window).scrollTop(state.scrollTop);
                    }

                    // trigger load event here - assume that new content has
                    // been added in transition_in
                    // TODO uid here?
                    $(window).trigger(Hashban.LOAD_EVENT);

                    // work around jquery's auto overflow switch - see
                    // http://goo.gl/V9UUw
                    contentWrap.css({
                        overflow: 'visible'
                    });

                    that.previous_url = url;
                }
                else {
                    // reload the page to show the error
                    window.location.href = url;
                }

            };

            function endfade() {
                // Called once the transition_out animation is completed,
                // or immediately if there is no transition_out.
                if (!completed) {
                    completed = true;
                    if (html) {
                        fadein();
                    }
                    else {
                        loaderTimer = setTimeout(function() {
                            that.options.loader(true);
                        }, that.options.loaderTimeout);
                        faded = true;
                    }
                }
            };

            var old_content = $(this.options.contentWrapSelector).children()
                                  .not(this.options.loader());

            if (this.CACHE[url]) {
                html = this.CACHE[url];
            }
            else {
                if (this.currentXHR) {
                    this.currentXHR.abort();
                }
                this.currentXHR = $.ajax(url, {
                    success: function(data) {
                        that.CACHE[url] = data;
                        html = data;
                        if (faded) {
                            fadein();
                        }
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        html = jqXHR.responseText;
                        error = errorThrown;
                        if (faded) {
                            fadein();
                        }
                    }
                });
            }

            if (typeof this.options.transition_out === 'function') {
                this.options.transition_out(endfade, old_content,
                                            transition_data);
            }
            else {
                endfade();
            }

        }
    };

    Hashban.prototype.buildState = function(params) {
        // builds the History state dict, starting with a common base and
        // adding the params obj

        return $.extend({
            handler: this.options['uid']
        }, params || {});
    };

    // PUBLIC INSTANCE METHODS

    Hashban.prototype.bindUntilUnload = function (el, event, callback) {
        // bind event to el, and unbind when navigating away from the page

        // TODO - account for uid here

        el.on(event, callback);
        $(window).one(Hashban.UNLOAD_EVENT, function() {
            el.off(event, callback);
        });
    };

    Hashban.prototype.preload = function (url) {
        // preload a url to avoid transition delay
        var that = this;

        if (!this.CACHE[url]) {
            $.ajax(url, {
                success: function(data) {
                    that.CACHE[url] = data;
                }
            });
        }
    };

    // PUBLIC UTILITIES

    Hashban.getBody = function (html) {
        // get wrapped body element from an html document

        return $('<div' +
                 getmatch(html, /<body([^>]*>[\S\s]*)<\/body>/, 1) +
                 '</div>');
    };

    // INTERNAL UTILITIES

    function getmatch(str, re, i) {
        // find and return the ith matched pattern in a regex, or
        // return a blank string if not found

        var match = str.match(re);
        if (match) {
            return match[i];
        }
        else {
            return '';
        }
    };

    function get_direction(from, to, link_order) {
        // Returns 1 (forwards) or -1 (backwards) for a given transition.
        // 0 is returned when the direction cannot be inferred.
        // link_order should be a list of the site's top-level link urls,
        // in order (see setup function).

        if (!link_order) {
            link_order = [];
        }

        if (to === from) {
            // this shouldn't really happen
            return 0;
        }
        else if (is_sublink(from, to)) {
            // if to is a child of from, go forward
            return 1;
        }
        else if (is_sublink(to, from)) {
            // if from is a child of to, go backwards
            return -1;
        }
        else {
            // otherwise, investigate the link_order setting to see
            // which way to go:
            var from_i = -1,
                to_i = -1;

            // first look for exact matches
            for (var i = 0; i < link_order.length; i++) {
                if (from_i === -1 && from === link_order[i]) {
                    from_i = i;
                }
                if (to_i === -1 && to === link_order[i]) {
                    to_i = i;
                }
            }
            if (from_i === -1 || to_i === -1) {
                // if no exact match, look for parent urls that match
                for (var i = 0; i < link_order.length; i++) {
                    if (from_i === -1 && is_sublink(link_order[i], from)) {
                        from_i = i;
                    }
                    if (to_i === -1 && is_sublink(link_order[i], to)) {
                        to_i = i;
                    }
                }
            }

            if (from_i === to_i || from_i === -1 || to_i === -1) {
                // can't determine a direction
                return 0;
            }
            else if (to_i < from_i) {
                // return backwards
                return -1;
            }
            else {
                // return forwards
                return 1;
            }

        }
    };

    function is_sublink(link, possible_sublink) {
        // Determine whether possible_sublink is a child of
        // link in the url tree. Returns false if the links
        // are the same.

        // add trailing slashes if they're missing, to ensure
        // that is_sublink(/test', '/test-2') returns false,
        // but is_sublink(/test', '/test/2') returns true.
        if (possible_sublink.slice(-1) !== '/') {
            possible_sublink += '/';
        }
        if (link.slice(-1) !== '/') {
            link += '/';
        }

        if (link !== possible_sublink && possible_sublink.indexOf(link) === 0) {
            return true;
        }
        else {
            return false;
        }
    };

    return Hashban;

})(jQuery);
<commit_msg>don't hijack blank links<commit_after>/*

hashban.js is a plugin to streamline the addition of ajax-style page transitions
to a website.

Example:

    var hashban = Hashban({
        contentWrapSelector: '#mycontent'
    });
    hashban.hijack($('#header nav'));
    hashban.bind();

Options/defaults:

    contentWrapSelector: '#content',
    duration: 500,
    transition_out: transition_out,
    transition_in: transition_in,
    loader: $.hashban.loader,
    link_order: [],
    link_filter: null,
    loaderTimeout: 300

*/

var Hashban = (function($) {

    function Hashban(user_options) {
        if (!(this instanceof Hashban)) return new Hashban(user_options);
        var that = this;

        function transition_out(endfade, old_content, data) {
            // Default transition out: fade the old content out, and call
            // end_callback once the transition is done

            old_content.fadeOut(that.options.duration, endfade);
        };

        function transition_in(new_content, old_content, data) {
            // Default transition in: remove the old content (in case it's
            // still there) and fade the new content in.

            old_content.remove();
            new_content.fadeIn(that.options.duration);
        };

        function loader(visible) {
            // this function toggles the "loading" state, based on
            // the parameter. If creating a loader element on the
            // page, it should return this element.

            // TODO uid for loader class?

            var loading = $('.hashban-loader');
            if (!loading.length) {
                loading = $('<span>').addClass('hashban-loader')
                                     .text('Loading').hide();
                $(that.options.contentWrapSelector).append(loading);
            }
            if (visible === true) {
                loading.show();
            }
            else if (visible === false) {
                loading.hide();
            }
            return loading;
        };

        this.CACHE = {};
        this.currentXHR = null;
        this.previous_url = window.location.pathname;
        this.options = $.extend({
            contentWrapSelector: '#content',
            duration: 500,
            transition_out: transition_out,
            transition_in: transition_in,
            content_init: null,
            loader: loader,
            link_order: [],
            loaderTimeout: 300,
            uid: 'Hashban.js'
        }, user_options);

    };

    Hashban.LOAD_EVENT = 'hashban-load';
    Hashban.UNLOAD_EVENT = 'hashban-unload';

    Hashban.prototype.bind = function(){
        var that = this;

        $(window).bind('popstate', function(e) {
            if (e.originalEvent.state &&
                e.originalEvent.state['handler'] === that.options['uid']) {
                that.loadPage(window.location.pathname, true);
                return false;
            }
        });
    };

    Hashban.prototype.hashban = function(links){
        // bind the given links (a jquery collection) to load via ajax

        var that = this;
        links.each(function() {
            var me = $(this),
                url = me.attr('href');

            // TODO uid here? can you bind two Hashbans to one link?

            if (!me.data('hashbanned')) {
                me.click(function() {
                    that.loadPage(url);
                    return false;
                });
                me.data('hashbanned', true);
            }
        });

    };

    Hashban.prototype.hijack = function(el, link_filter) {
        // find suitable links within the given element(s), and hijack them
        // to load via ajax

        var domain = getmatch(window.location.href, /[^\/]+\/\/[^\/]+/, 0),
            links = el.find('a[href]:not([href^="http://"]), ' +
                            'a[href^="' + domain + '"]')
                        .not('[href$=".xml"], [href$=".pdf"], ' +
                             '[href$=".jpg"], [href$=".gif"], ' +
                             '[href$=".png"], [href^="#"]');

        if (link_filter) {
            links = links.filter(link_filter);
        }

        this.hashban(links);

        return el;
    };

    Hashban.prototype.loadPage = function (url, state) {
        // Load the specified url. If state is passed, it is assumed to be the
        // state dictionary from the popstate event, (i.e. back button) and the
        // pageload is handled accordingly. Otherwise, it is assumed the
        // pageLoad was initiated by the user clicking a link.

        var that = this,
            contentWrap = $(this.options.contentWrapSelector),
            html,
            error,
            loaderTimer,
            faded = false,
            completed = false,
            transition_data = {
                direction: get_direction(this.previous_url, url,
                                         this.options.link_order),
                from: this.previous_url,
                to: url,
                state: state
            };

        if (this.previous_url !== url) {

            // save scroll position in current state; also means the transition
            // will work if the user navigates to the originally loaded page
            // via the back button
            if (!state) {
                window.history.replaceState(that.buildState({
                    scrollTop: $(window).scrollTop()
                }), null, window.location);
            }

            // Order of events
            // 1. start loading
            // 2. transition out old content
            // 3. show spinner
            // 4. once load and transition out are both done, transition in

            function fadein() {
                var contentBody = Hashban.getBody(html),
                    bodyClass = contentBody.attr('class'),
                    contentEl = contentBody.find(
                                    that.options.contentWrapSelector),
                    title = getmatch(html, /<title>([\s\S]*?)<\/title>/, 1);

                if (contentEl.length) {
                    if (!state) {
                        // assume a link was clicked if no state present
                        history.pushState(that.buildState(), null, url);
                    }
                    document.title = $('<div>').html(title).text();

                    $('body').attr('class', bodyClass);

                    clearTimeout(loaderTimer);
                    that.options.loader(false);

                    var new_content = contentEl.children(),
                        old_content = contentWrap.children()
                                                 .not(that.options.loader());

                    // trigger unload event here so that it won't effect any
                    // new content
                    // TODO uid here?
                    $(window).trigger(Hashban.UNLOAD_EVENT);

                    new_content.appendTo(contentWrap).hide();

                    transition_data.contentBody = contentBody;
                    that.options.transition_in(new_content, old_content,
                                               transition_data);

                    if (typeof that.options.content_init === 'function') {
                        that.options.content_init(new_content);
                    }

                    // if the load was triggered by popstate, eg. the back
                    // button and not a clicked link, restore scroll position
                    if (state && state.scrollTop) {
                        $(window).scrollTop(state.scrollTop);
                    }

                    // trigger load event here - assume that new content has
                    // been added in transition_in
                    // TODO uid here?
                    $(window).trigger(Hashban.LOAD_EVENT);

                    // work around jquery's auto overflow switch - see
                    // http://goo.gl/V9UUw
                    contentWrap.css({
                        overflow: 'visible'
                    });

                    that.previous_url = url;
                }
                else {
                    // reload the page to show the error
                    window.location.href = url;
                }

            };

            function endfade() {
                // Called once the transition_out animation is completed,
                // or immediately if there is no transition_out.
                if (!completed) {
                    completed = true;
                    if (html) {
                        fadein();
                    }
                    else {
                        loaderTimer = setTimeout(function() {
                            that.options.loader(true);
                        }, that.options.loaderTimeout);
                        faded = true;
                    }
                }
            };

            var old_content = $(this.options.contentWrapSelector).children()
                                  .not(this.options.loader());

            if (this.CACHE[url]) {
                html = this.CACHE[url];
            }
            else {
                if (this.currentXHR) {
                    this.currentXHR.abort();
                }
                this.currentXHR = $.ajax(url, {
                    success: function(data) {
                        that.CACHE[url] = data;
                        html = data;
                        if (faded) {
                            fadein();
                        }
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        html = jqXHR.responseText;
                        error = errorThrown;
                        if (faded) {
                            fadein();
                        }
                    }
                });
            }

            if (typeof this.options.transition_out === 'function') {
                this.options.transition_out(endfade, old_content,
                                            transition_data);
            }
            else {
                endfade();
            }

        }
    };

    Hashban.prototype.buildState = function(params) {
        // builds the History state dict, starting with a common base and
        // adding the params obj

        return $.extend({
            handler: this.options['uid']
        }, params || {});
    };

    // PUBLIC INSTANCE METHODS

    Hashban.prototype.bindUntilUnload = function (el, event, callback) {
        // bind event to el, and unbind when navigating away from the page

        // TODO - account for uid here

        el.on(event, callback);
        $(window).one(Hashban.UNLOAD_EVENT, function() {
            el.off(event, callback);
        });
    };

    Hashban.prototype.preload = function (url) {
        // preload a url to avoid transition delay
        var that = this;

        if (!this.CACHE[url]) {
            $.ajax(url, {
                success: function(data) {
                    that.CACHE[url] = data;
                }
            });
        }
    };

    // PUBLIC UTILITIES

    Hashban.getBody = function (html) {
        // get wrapped body element from an html document

        return $('<div' +
                 getmatch(html, /<body([^>]*>[\S\s]*)<\/body>/, 1) +
                 '</div>');
    };

    // INTERNAL UTILITIES

    function getmatch(str, re, i) {
        // find and return the ith matched pattern in a regex, or
        // return a blank string if not found

        var match = str.match(re);
        if (match) {
            return match[i];
        }
        else {
            return '';
        }
    };

    function get_direction(from, to, link_order) {
        // Returns 1 (forwards) or -1 (backwards) for a given transition.
        // 0 is returned when the direction cannot be inferred.
        // link_order should be a list of the site's top-level link urls,
        // in order (see setup function).

        if (!link_order) {
            link_order = [];
        }

        if (to === from) {
            // this shouldn't really happen
            return 0;
        }
        else if (is_sublink(from, to)) {
            // if to is a child of from, go forward
            return 1;
        }
        else if (is_sublink(to, from)) {
            // if from is a child of to, go backwards
            return -1;
        }
        else {
            // otherwise, investigate the link_order setting to see
            // which way to go:
            var from_i = -1,
                to_i = -1;

            // first look for exact matches
            for (var i = 0; i < link_order.length; i++) {
                if (from_i === -1 && from === link_order[i]) {
                    from_i = i;
                }
                if (to_i === -1 && to === link_order[i]) {
                    to_i = i;
                }
            }
            if (from_i === -1 || to_i === -1) {
                // if no exact match, look for parent urls that match
                for (var i = 0; i < link_order.length; i++) {
                    if (from_i === -1 && is_sublink(link_order[i], from)) {
                        from_i = i;
                    }
                    if (to_i === -1 && is_sublink(link_order[i], to)) {
                        to_i = i;
                    }
                }
            }

            if (from_i === to_i || from_i === -1 || to_i === -1) {
                // can't determine a direction
                return 0;
            }
            else if (to_i < from_i) {
                // return backwards
                return -1;
            }
            else {
                // return forwards
                return 1;
            }

        }
    };

    function is_sublink(link, possible_sublink) {
        // Determine whether possible_sublink is a child of
        // link in the url tree. Returns false if the links
        // are the same.

        // add trailing slashes if they're missing, to ensure
        // that is_sublink(/test', '/test-2') returns false,
        // but is_sublink(/test', '/test/2') returns true.
        if (possible_sublink.slice(-1) !== '/') {
            possible_sublink += '/';
        }
        if (link.slice(-1) !== '/') {
            link += '/';
        }

        if (link !== possible_sublink && possible_sublink.indexOf(link) === 0) {
            return true;
        }
        else {
            return false;
        }
    };

    return Hashban;

})(jQuery);
<|endoftext|>


<commit_before>
/**
 * Afrikaans
 */
export const af_za = {
    locale: 'af-ZA',
    messages: {
        after: "Moet na ${date} wees",
        alpha: "Mag net letters gebruik",
        alphanumeric: "Mag net letters of syfers gebruik",
        array: "Moet 'n array wees",
        ascii: "Mag net ASCII karakters genruik",
        base64: "Moet Base64 data wees",
        before: "Moet voor ${date} wees",
        between: "Moet tussen ${min} en ${max} wees",
        between_inclusive: "Moet tussen of gelyk aan ${min} en ${max} wees",
        boolean: "Moet 'true' of 'false' wees",
        creditcard: "Moet 'n geldige kredietkaardnommer wees",
        date: "Met 'n geldige datum wees",
        dateformat: "Moet 'n geldige datum wees (${format})",
        defined: "Benodig 'n waarde",
        email: "Moet 'n geldig email adres wees",
        empty: "Moet leeg wees",
        equals: "Moet gelyk aan ${other} wees",
        gt: "Moet meer as ${min} wees",
        gte: "Moet meer as of gelyk aan ${min} wees",
        integer: "Moet 'n heelgetal wees",
        ip: "Moet 'n geldige IP adres wees",
        isblank: "Benodig 'n waarde",
        isnil: "Benodig 'n waarde",
        isnull: "Benodig 'n waarde",
        iso8601: "Moet 'n geldige ISO8601 datum wees",
        json: "Moet geldige JSON wees",
        length: "Moet 'n lengte van tenminste ${min} hê",
        length_between: "Moet 'n length tussen ${min} en ${max} hê",
        lt: "Moet minder as ${max} wees",
        lte: "Moet minder as of gelyk aan ${max} wees",
        match: "Moet ooreenstem met '${pattern}'",
        negative: "Moet 'n negatiewe getal wees",
        not: "Man nie ${value} wees nie",
        number: "Moet 'n nommer wees",
        numeric: "Moet 'n numeriese waarde hê",
        object: "Moet 'n 'object' wees",
        positive: "Moet 'n positiewe getal wees",
        required: "Benodig 'n waarde",
        same: "Moet dieselfde waarde as '${other}' wees",
        string: "Moet 'n 'string' wees",
        url: "Moet 'n geldige URL wees",
        uuid: "Moet 'n geldige UUID wees",
    },
}

/**
 * English - United States (Default)
 */
export const en_us = {
    locale: 'en-US',
    messages: {
        after: 'Must be after ${date}',
        alpha: 'Can only use letters',
        alphanumeric: 'Must be alphanumeric',
        array: 'Must be an array',
        ascii: 'Must be ASCII',
        base64: 'Must be valid Base64',
        before: 'Must be before ${date}',
        between: 'Must be between ${min} and ${max}',
        between_inclusive: 'Must be between ${min} and ${max}, inclusive',
        boolean: 'Must be true or false',
        creditcard: 'Must be a valid credit card number',
        date: 'Must be a valid date',
        dateformat: 'Must use "${format}" format',
        defined: 'Required',
        email: 'Must be a valid email address',
        empty: 'Must be empty',
        equals: 'Must be equal to ${other}',
        gt: 'Must be greater than ${min}',
        gte: 'Must be greater than or equal to ${min}',
        integer: 'Must be an integer',
        ip: 'Must be a valid IP address',
        isblank: 'May not be blank',
        isnil: 'Required',
        isnull: 'Required',
        iso8601: 'Must be a valid ISO8601 date',
        json: 'Must be a valid JSON',
        length: 'Must have a length of at least ${min}',
        length_between: 'Must have a length between ${min} and ${max}',
        lt: 'Must be less than ${max}',
        lte: 'Must be less than or equal to ${max}',
        match: 'Must match "${pattern}"',
        negative: 'Must be a negative number',
        not: 'Can not be ${value}',
        number: 'Must be a number',
        numeric: 'Must be numeric',
        object: 'Must be an object',
        positive: 'Must be a positive number',
        required: 'Required',
        same: 'Must have the same value as "${other}"',
        string: 'Must be a string',
        url: 'Must be a valid URL',
        uuid: 'Must be a valid UUID',
    },
}

/**
 * Portuguese - Brazil
 */
export const pt_br = {
    locale: 'pt-BR',
    messages: {
        after: 'Deve ser uma data depois de ${date}',
        alpha: 'Deve conter somente letras',
        alphanumeric: 'Deve conter somente letras e números',
        array: 'Deve ser um array',
        ascii: 'Deve ser ASCII',
        base64: 'Deve ser um Base64 válido',
        before: 'Deve ser uma data antes de ${date}',
        between: 'Deve estar entre ${min} e ${max}',
        between_inclusive: 'Deve estar entre ${min} e ${max}, inclusive',
        boolean: 'Deve ser verdadeiro ou falso',
        creditcard: 'Deve ser um número de cartão de crédito válido',
        date: 'Deve ser uma data válida',
        dateformat: 'Deve usar o formato "${format}"',
        defined: 'Campo obrigatório',
        email: 'Deve ser um endereço de email válido',
        empty: 'Deve ser vazio',
        equals: 'Deve ser igual a ${other}',
        gt: 'Deve ser maior que ${min}',
        gte: 'Deve ser maior ou igual a ${min}',
        integer: 'Deve ser um inteiro',
        ip: 'Deve ser um endereço de IP válido',
        isblank: 'Deve estar em branco',
        isnil: 'Campo obrigatório',
        isnull: 'Campo obrigatório',
        iso8601: 'Deve ser uma data ISO8601 válida',
        json: 'Deve ser um JSON válido',
        length: 'Deve ter o tamanho de pelo menos ${min}',
        length_between: 'Deve ter o tamanho entre ${min} e ${max}',
        lt: 'Deve ser menor que ${max}',
        lte: 'Deve ser menor ou igual a ${max}',
        match: 'Deve ter o formato "${pattern}"',
        negative: 'Deve ser um número negativo',
        not: 'Não pode ser ${value}',
        number: 'Deve ser um número',
        numeric: 'Deve ser numérico',
        object: 'Deve ser um object',
        positive: 'Deve ser um número positivo',
        required: 'Campo obrigatório',
        same: 'Deve ser igual a "${other}"',
        string: 'Deve ser uma string',
        url: 'Deve ser uma URL válida',
        uuid: 'Deve ser um UUID válido',
    },
}

/**
 * Dutch - The Netherlands (Default)
 */
export const nl_nl = {
    locale: 'nl-NL',
    messages: {
        after: 'Moet na ${date} zijn',
        alpha: 'Kan alleen letters gebruiken',
        alphanumeric: 'Moet cijfers en/of letters zijn',
        array: 'Moet een lijst zijn',
        ascii: 'Moet ASCII zijn',
        base64: 'Moet geldige Base64 zijn',
        before: 'Moet voor ${date} zijn',
        between: 'Moet tussen ${min} en ${max} zijn',
        between_inclusive: 'Moet tussen of gelijk aan ${min} en ${max} zijn',
        boolean: 'Moet waar of onwaar zijn',
        creditcard: 'Moet een geldig credit card nummer zijn',
        date: 'Moet een geldige datum zijn',
        dateformat: 'Moet "${format}" indeling zijn',
        defined: 'Vereist',
        email: 'Moet een geldig emailadres zijn',
        empty: 'Moet leeg zijn',
        equals: 'Moet gelijk zijn aan ${other}',
        gt: 'Moet groter zijn dan ${min}',
        gte: 'Moet groter of gelijk zijn aan ${min}',
        integer: 'Moet een geheel getal zijn',
        ip: 'Moet een geldig IP address zijn',
        isblank: 'Mag niet leeg zijn',
        isnil: 'Vereist',
        isnull: 'Vereist',
        iso8601: 'Moet een geldige ISO8601 datum zijn',
        json: 'Moet een geldige JSON zijn',
        length: 'Moet ten minste ${min} karakters lang zijn',
        length_between: 'Moet tussen ${min} en ${max} karakters lang zijn',
        lt: 'Moet minder dan ${max}',
        lte: 'Moet minder of gelijk aan ${max} zijn',
        match: 'Moet overeenkomen met dit patroon "${pattern}"',
        negative: 'Moet een negatief getal zijn zijn',
        not: 'Mag niet ${value} zijn',
        number: 'Moet een getal zijn',
        numeric: 'Moet een getal zijn',
        object: 'Moet een object zijn',
        positive: 'Moet een positief nummer zijn',
        required: 'Vereist',
        same: 'Moet dezelfde waarde hebben als "${other}"',
        string: 'Moet een string zijn',
        url: 'Moet een geldige URL zijn',
        uuid: 'Moet een geldige UUID zijn',
    },
}<commit_msg>add the ru-RU locale<commit_after>
/**
 * Afrikaans
 */
export const af_za = {
    locale: 'af-ZA',
    messages: {
        after: "Moet na ${date} wees",
        alpha: "Mag net letters gebruik",
        alphanumeric: "Mag net letters of syfers gebruik",
        array: "Moet 'n array wees",
        ascii: "Mag net ASCII karakters genruik",
        base64: "Moet Base64 data wees",
        before: "Moet voor ${date} wees",
        between: "Moet tussen ${min} en ${max} wees",
        between_inclusive: "Moet tussen of gelyk aan ${min} en ${max} wees",
        boolean: "Moet 'true' of 'false' wees",
        creditcard: "Moet 'n geldige kredietkaardnommer wees",
        date: "Met 'n geldige datum wees",
        dateformat: "Moet 'n geldige datum wees (${format})",
        defined: "Benodig 'n waarde",
        email: "Moet 'n geldig email adres wees",
        empty: "Moet leeg wees",
        equals: "Moet gelyk aan ${other} wees",
        gt: "Moet meer as ${min} wees",
        gte: "Moet meer as of gelyk aan ${min} wees",
        integer: "Moet 'n heelgetal wees",
        ip: "Moet 'n geldige IP adres wees",
        isblank: "Benodig 'n waarde",
        isnil: "Benodig 'n waarde",
        isnull: "Benodig 'n waarde",
        iso8601: "Moet 'n geldige ISO8601 datum wees",
        json: "Moet geldige JSON wees",
        length: "Moet 'n lengte van tenminste ${min} hê",
        length_between: "Moet 'n length tussen ${min} en ${max} hê",
        lt: "Moet minder as ${max} wees",
        lte: "Moet minder as of gelyk aan ${max} wees",
        match: "Moet ooreenstem met '${pattern}'",
        negative: "Moet 'n negatiewe getal wees",
        not: "Man nie ${value} wees nie",
        number: "Moet 'n nommer wees",
        numeric: "Moet 'n numeriese waarde hê",
        object: "Moet 'n 'object' wees",
        positive: "Moet 'n positiewe getal wees",
        required: "Benodig 'n waarde",
        same: "Moet dieselfde waarde as '${other}' wees",
        string: "Moet 'n 'string' wees",
        url: "Moet 'n geldige URL wees",
        uuid: "Moet 'n geldige UUID wees",
    },
}

/**
 * English - United States (Default)
 */
export const en_us = {
    locale: 'en-US',
    messages: {
        after: 'Must be after ${date}',
        alpha: 'Can only use letters',
        alphanumeric: 'Must be alphanumeric',
        array: 'Must be an array',
        ascii: 'Must be ASCII',
        base64: 'Must be valid Base64',
        before: 'Must be before ${date}',
        between: 'Must be between ${min} and ${max}',
        between_inclusive: 'Must be between ${min} and ${max}, inclusive',
        boolean: 'Must be true or false',
        creditcard: 'Must be a valid credit card number',
        date: 'Must be a valid date',
        dateformat: 'Must use "${format}" format',
        defined: 'Required',
        email: 'Must be a valid email address',
        empty: 'Must be empty',
        equals: 'Must be equal to ${other}',
        gt: 'Must be greater than ${min}',
        gte: 'Must be greater than or equal to ${min}',
        integer: 'Must be an integer',
        ip: 'Must be a valid IP address',
        isblank: 'May not be blank',
        isnil: 'Required',
        isnull: 'Required',
        iso8601: 'Must be a valid ISO8601 date',
        json: 'Must be a valid JSON',
        length: 'Must have a length of at least ${min}',
        length_between: 'Must have a length between ${min} and ${max}',
        lt: 'Must be less than ${max}',
        lte: 'Must be less than or equal to ${max}',
        match: 'Must match "${pattern}"',
        negative: 'Must be a negative number',
        not: 'Can not be ${value}',
        number: 'Must be a number',
        numeric: 'Must be numeric',
        object: 'Must be an object',
        positive: 'Must be a positive number',
        required: 'Required',
        same: 'Must have the same value as "${other}"',
        string: 'Must be a string',
        url: 'Must be a valid URL',
        uuid: 'Must be a valid UUID',
    },
}

/**
 * Portuguese - Brazil
 */
export const pt_br = {
    locale: 'pt-BR',
    messages: {
        after: 'Deve ser uma data depois de ${date}',
        alpha: 'Deve conter somente letras',
        alphanumeric: 'Deve conter somente letras e números',
        array: 'Deve ser um array',
        ascii: 'Deve ser ASCII',
        base64: 'Deve ser um Base64 válido',
        before: 'Deve ser uma data antes de ${date}',
        between: 'Deve estar entre ${min} e ${max}',
        between_inclusive: 'Deve estar entre ${min} e ${max}, inclusive',
        boolean: 'Deve ser verdadeiro ou falso',
        creditcard: 'Deve ser um número de cartão de crédito válido',
        date: 'Deve ser uma data válida',
        dateformat: 'Deve usar o formato "${format}"',
        defined: 'Campo obrigatório',
        email: 'Deve ser um endereço de email válido',
        empty: 'Deve ser vazio',
        equals: 'Deve ser igual a ${other}',
        gt: 'Deve ser maior que ${min}',
        gte: 'Deve ser maior ou igual a ${min}',
        integer: 'Deve ser um inteiro',
        ip: 'Deve ser um endereço de IP válido',
        isblank: 'Deve estar em branco',
        isnil: 'Campo obrigatório',
        isnull: 'Campo obrigatório',
        iso8601: 'Deve ser uma data ISO8601 válida',
        json: 'Deve ser um JSON válido',
        length: 'Deve ter o tamanho de pelo menos ${min}',
        length_between: 'Deve ter o tamanho entre ${min} e ${max}',
        lt: 'Deve ser menor que ${max}',
        lte: 'Deve ser menor ou igual a ${max}',
        match: 'Deve ter o formato "${pattern}"',
        negative: 'Deve ser um número negativo',
        not: 'Não pode ser ${value}',
        number: 'Deve ser um número',
        numeric: 'Deve ser numérico',
        object: 'Deve ser um object',
        positive: 'Deve ser um número positivo',
        required: 'Campo obrigatório',
        same: 'Deve ser igual a "${other}"',
        string: 'Deve ser uma string',
        url: 'Deve ser uma URL válida',
        uuid: 'Deve ser um UUID válido',
    },
}

/**
 * Dutch - The Netherlands (Default)
 */
export const nl_nl = {
    locale: 'nl-NL',
    messages: {
        after: 'Moet na ${date} zijn',
        alpha: 'Kan alleen letters gebruiken',
        alphanumeric: 'Moet cijfers en/of letters zijn',
        array: 'Moet een lijst zijn',
        ascii: 'Moet ASCII zijn',
        base64: 'Moet geldige Base64 zijn',
        before: 'Moet voor ${date} zijn',
        between: 'Moet tussen ${min} en ${max} zijn',
        between_inclusive: 'Moet tussen of gelijk aan ${min} en ${max} zijn',
        boolean: 'Moet waar of onwaar zijn',
        creditcard: 'Moet een geldig credit card nummer zijn',
        date: 'Moet een geldige datum zijn',
        dateformat: 'Moet "${format}" indeling zijn',
        defined: 'Vereist',
        email: 'Moet een geldig emailadres zijn',
        empty: 'Moet leeg zijn',
        equals: 'Moet gelijk zijn aan ${other}',
        gt: 'Moet groter zijn dan ${min}',
        gte: 'Moet groter of gelijk zijn aan ${min}',
        integer: 'Moet een geheel getal zijn',
        ip: 'Moet een geldig IP address zijn',
        isblank: 'Mag niet leeg zijn',
        isnil: 'Vereist',
        isnull: 'Vereist',
        iso8601: 'Moet een geldige ISO8601 datum zijn',
        json: 'Moet een geldige JSON zijn',
        length: 'Moet ten minste ${min} karakters lang zijn',
        length_between: 'Moet tussen ${min} en ${max} karakters lang zijn',
        lt: 'Moet minder dan ${max}',
        lte: 'Moet minder of gelijk aan ${max} zijn',
        match: 'Moet overeenkomen met dit patroon "${pattern}"',
        negative: 'Moet een negatief getal zijn zijn',
        not: 'Mag niet ${value} zijn',
        number: 'Moet een getal zijn',
        numeric: 'Moet een getal zijn',
        object: 'Moet een object zijn',
        positive: 'Moet een positief nummer zijn',
        required: 'Vereist',
        same: 'Moet dezelfde waarde hebben als "${other}"',
        string: 'Moet een string zijn',
        url: 'Moet een geldige URL zijn',
        uuid: 'Moet een geldige UUID zijn',
    },
}

/**
 * Russian - Russia
 */
export const ru_ru = {
    locale: 'ru-RU',
    messages: {
        after: 'Должен быть после ${date}',
        alpha: 'Разрешаются только буквы',
        alphanumeric: 'Разрешаются только цифро-буквенные символы',
        array: 'Должен быть массивом',
        ascii: 'Должен быть ASCII',
        base64: 'Должен быть Base64',
        before: 'Должен быть до ${date}',
        between: 'Должен быть от ${min} до ${max}',
        between_inclusive: 'Должен быть от ${min} до ${max}, включительно',
        boolean: 'Должен быть true либо false',
        creditcard: 'Должен быть действительным номером кредитной карты',
        date: 'Должен быть действительной датой',
        dateformat: 'Должен использовать формат "${format}"',
        defined: 'Обязателен',
        email: 'Должен быть действительным email адресом',
        empty: 'Должен быть пустым',
        equals: 'Должен быть равным ${other}',
        gt: 'Должен быть больше ${min}',
        gte: 'Должен быть больше или равен ${min}',
        integer: 'Должен быть целым числом',
        ip: 'Должен быть действительным IP адресом',
        isblank: 'Не может быть пустым',
        isnil: 'Обязателен',
        isnull: 'Обязателен',
        iso8601: 'Должен быть действительной ISO8601 датой',
        json: 'Должен быть действительным JSON объектом',
        length: 'Должен иметь минимальную длинну в ${min} символов',
        length_between: 'Должен иметь длинну между ${min} и ${max}',
        lt: 'Должен быть меньше ${max}',
        lte: 'Должен быть меньше или равен ${max}',
        match: 'Должен совпадать с "${pattern}"',
        negative: 'Должен быть отрицательным числом',
        not: 'Не может быть ${value}',
        number: 'Должен быть числом',
        numeric: 'Должен быть числовым',
        object: 'Должен быть объектом',
        positive: 'Должен быть положительным числом',
        required: 'Обязателен',
        same: 'Должен иметь такое же значение как и "${other}"',
        string: 'Должен быть строкой',
        url: 'Должен быть действительным URL',
        uuid: 'Должен быть действительным UUID',
    },
}
<|endoftext|>


<commit_before>/*
 * grunt-jscoverage-report
 *
 *
 * Copyright (c) 2013 m1kc (Max Musatov)
 * Licensed under the AGPLv3 license.
 */

'use strict';

module.exports = function(grunt) {
	// Please see the Grunt documentation for more information regarding task
	// creation: http://gruntjs.com/creating-tasks
	grunt.registerTask('jscoverage_report', 'Shows jscoverage report.', function() {
		grunt.task.requires('nodeunit');
		var jsc = require('jscoverage');
		jsc.coverage(); // print summary info, cover percent
		jsc.coverageDetail(); // print uncovered lines
	});
};
<commit_msg>Typo.<commit_after>/*
 * grunt-jscoverage-report
 *
 *
 * Copyright (c) 2013 m1kc (Max Musatov)
 * Licensed under the AGPLv3 license.
 */

'use strict';

module.exports = function(grunt) {
	// Please see the Grunt documentation for more information regarding task
	// creation: http://gruntjs.com/creating-tasks
	grunt.registerTask('jscoverage_report', 'Show jscoverage report.', function() {
		grunt.task.requires('nodeunit');
		var jsc = require('jscoverage');
		jsc.coverage(); // print summary info, cover percent
		jsc.coverageDetail(); // print uncovered lines
	});
};
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var sass = require('gulp-sass');
var useref = require('gulp-useref');
var cssnano = require('gulp-cssnano');
var del = require('del');
var flatten = require('gulp-flatten');
var browserify = require('browserify');
var source = require('vinyl-source-stream');

var outputFolder = 'dist';
var contentFolder = 'content';
var sassFiles = contentFolder + '/**/*.scss';
var cssOutputFolder = outputFolder + '/css';
var jsOutputFolder = outputFolder + '/js';
var htmlFiles = contentFolder + '/**/*.html';
var jsMainFile = 'content/app/app.js';
var jsFiles = contentFolder + '/**/*.js';

gulp.task('clean', function () {
    return del([outputFolder]);
});

gulp.task('sass', function(){
    return gulp.src(sassFiles)
        .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
        .pipe(cssnano())
        .pipe(flatten())
        .pipe(gulp.dest(cssOutputFolder));
});

gulp.task('sass:watch', function () {
    return gulp.watch(sassFiles, ['sass']);
});

gulp.task('html', function(){
    return gulp.src(htmlFiles)
        .pipe(gulp.dest(outputFolder));
});

gulp.task('html:watch', function(){
    return gulp.watch(htmlFiles, ['html']);
});

gulp.task('js', function(){
    return browserify(jsMainFile)
        .bundle()
        .pipe(source('app.js'))
        .pipe(gulp.dest(jsOutputFolder));
});

gulp.task('js:watch', function(){
    return gulp.watch(jsFiles), ['js'];
});

gulp.task('watch', ['sass:watch', 'js:watch', 'html:watch']);

gulp.task('default', ['sass', 'html', 'js'])
<commit_msg>Gulpfile changes<commit_after>'use strict';

var gulp = require('gulp');
var sass = require('gulp-sass');
var cssnano = require('gulp-cssnano');
var del = require('del');
var flatten = require('gulp-flatten');
var browserify = require('browserify');
var source = require('vinyl-source-stream');

var outputFolder = 'dist';
var contentFolder = 'content';
var sassFiles = contentFolder + '/**/*.scss';
var cssOutputFolder = outputFolder + '/css';
var jsOutputFolder = outputFolder + '/js';
var htmlFiles = contentFolder + '/**/*.html';
var jsMainFile = 'content/app/app.js';
var jsFiles = contentFolder + '/**/*.js';

gulp.task('clean', function () {
    return del([outputFolder]);
});

gulp.task('sass', function(){
    return gulp.src(sassFiles)
        .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
        .pipe(cssnano())
        .pipe(flatten())
        .pipe(gulp.dest(cssOutputFolder));
});

gulp.task('sass:watch', function () {
    return gulp.watch(sassFiles, ['sass']);
});

gulp.task('html', function(){
    return gulp.src(htmlFiles)
        .pipe(gulp.dest(outputFolder));
});

gulp.task('html:watch', function(){
    return gulp.watch(htmlFiles, ['html']);
});

gulp.task('js', function(){
    return browserify(jsMainFile)
        .bundle()
        .pipe(source('app.js'))
        .pipe(gulp.dest(jsOutputFolder));
});

gulp.task('js:watch', function(){
    return gulp.watch(jsFiles, ['js']);
});

gulp.task('watch', ['sass:watch', 'js:watch', 'html:watch']);

gulp.task('default', ['sass', 'html', 'js'])
<|endoftext|>


<commit_before><commit_msg>modify domain<commit_after><|endoftext|>