<commit_before>function read(URL, callback) {
    /**
    reads the contents of the file at the URL,
    converts it into a string, and then
    calls the callback function (which has no arguments)
    with "this" equalling the responseText
    */
    var file = new XMLHttpRequest();
    file.open("GET", URL);  // Don't add false as an extra argument (browsers don't like it). (default: asynchronous=true)
    file.onreadystatechange = function () {
        if(file.readyState === 4) {  // Is it done?
            if(file.status === 200 || file.status == 0) {  // Was it successful?
                // file.responseXML might have something
                callback.call(file.responseText);  // .call(calling object / value of "this", function arguments (listed individually))  .apply has function arguments in an array
                // You could also use callback(argument(s)) like a normal function, but it wouldn't change the value of "this".
            }
        }
    }
    file.send();
}

function pageJump(ID) {
    /**
    makes a section to jump to certain parts of the page
    */
    document.getElementsByTagName("h1")[0].id = "top";
    var division = document.getElementById(ID);
    var contents = document.createElement("div");
    contents.className = "list";
    contents.innerHTML = "

Jump to:
";
    var sections = division.getElementsByTagName("h2");
    var toTop = document.createElement("a");
    toTop.href = "#top";
    toTop.innerHTML = "To top";
    var listItems = "";  // I need this variable to hold the list items because trying to add
 at the beginning and
 at the end separately causes it to fill in the
 immediately after the
 and omit the real

    for (var index=0; index<sections.length; index++) {  // I would use (var in array), but index exceeds entries.length for no apparent reason
        var inside = sections[index].innerHTML.trim();  // The inner HTML has a bunch of whitespace for no apparent reason.
        sections[index].id = inside;
        listItems += "
" + inside + "
";
        division.insertBefore(toTop.cloneNode(true), division.getElementsByTagName("h2")[index].nextSibling);  // inserts after

        // toTop needs to be cloned so it doesn't keep getting reasigned to the next place (it also needs to have true to clone all children of the node, although it doesn't apply here)
    }
    contents.innerHTML += "
" + listItems + "

";
    document.body.insertBefore(contents, division);  // .insertBefore() only works for the immediate descendants of the parent
}

//This is able to run without waiting for anything else to load.

// makes my custom tag which overlines things
document.createElement("over");

// adds the universal formatting
var style = document.createElement("link");
style.rel = "stylesheet";
style.href = "formatting.css";
document.head.insertBefore(style, document.head.children[0]);

// links the favicon
// var icon = document.createElement("link");
// icon.rel = "icon";
// icon.href = "images/favicon.ico";
// document.head.insertBefore(icon, document.head.children[0]);

window.addEventListener("load", function() {  // This waits for everything past the script import to load before running.

    // surrounds every list with

    var orderedLists = document.getElementsByTagName("ol");
    var unorderedLists = document.getElementsByTagName("ul");
    for (var index=0; index<orderedLists.length; index++) {
        orderedLists[index].outerHTML = "
" + orderedLists[index].outerHTML + "
";
    }
    for (var index=0; index<unorderedLists.length; index++) {
        unorderedLists[index].outerHTML = "
" + unorderedLists[index].outerHTML + "
";
    }
});
<commit_msg>made the stylesheet href a URL<commit_after>function read(URL, callback) {
    /**
    reads the contents of the file at the URL,
    converts it into a string, and then
    calls the callback function (which has no arguments)
    with "this" equalling the responseText
    */
    var file = new XMLHttpRequest();
    file.open("GET", URL);  // Don't add false as an extra argument (browsers don't like it). (default: asynchronous=true)
    file.onreadystatechange = function () {
        if(file.readyState === 4) {  // Is it done?
            if(file.status === 200 || file.status == 0) {  // Was it successful?
                // file.responseXML might have something
                callback.call(file.responseText);  // .call(calling object / value of "this", function arguments (listed individually))  .apply has function arguments in an array
                // You could also use callback(argument(s)) like a normal function, but it wouldn't change the value of "this".
            }
        }
    }
    file.send();
}

function pageJump(ID) {
    /**
    makes a section to jump to certain parts of the page
    */
    document.getElementsByTagName("h1")[0].id = "top";
    var division = document.getElementById(ID);
    var contents = document.createElement("div");
    contents.className = "list";
    contents.innerHTML = "

Jump to:
";
    var sections = division.getElementsByTagName("h2");
    var toTop = document.createElement("a");
    toTop.href = "#top";
    toTop.innerHTML = "To top";
    var listItems = "";  // I need this variable to hold the list items because trying to add
 at the beginning and
 at the end separately causes it to fill in the
 immediately after the
 and omit the real

    for (var index=0; index<sections.length; index++) {  // I would use (var in array), but index exceeds entries.length for no apparent reason
        var inside = sections[index].innerHTML.trim();  // The inner HTML has a bunch of whitespace for no apparent reason.
        sections[index].id = inside;
        listItems += "
" + inside + "
";
        division.insertBefore(toTop.cloneNode(true), division.getElementsByTagName("h2")[index].nextSibling);  // inserts after

        // toTop needs to be cloned so it doesn't keep getting reasigned to the next place (it also needs to have true to clone all children of the node, although it doesn't apply here)
    }
    contents.innerHTML += "
" + listItems + "

";
    document.body.insertBefore(contents, division);  // .insertBefore() only works for the immediate descendants of the parent
}

//This is able to run without waiting for anything else to load.

// makes my custom tag which overlines things
document.createElement("over");

// adds the universal formatting
var style = document.createElement("link");
style.rel = "stylesheet";
style.href = "https://coolprogramminguser.github.io/Standards/formatting.css";
document.head.insertBefore(style, document.head.children[0]);

// links the favicon
// var icon = document.createElement("link");
// icon.rel = "icon";
// icon.href = "images/favicon.ico";
// document.head.insertBefore(icon, document.head.children[0]);

window.addEventListener("load", function() {  // This waits for everything past the script import to load before running.

    // surrounds every list with

    var orderedLists = document.getElementsByTagName("ol");
    var unorderedLists = document.getElementsByTagName("ul");
    for (var index=0; index<orderedLists.length; index++) {
        orderedLists[index].outerHTML = "
" + orderedLists[index].outerHTML + "
";
    }
    for (var index=0; index<unorderedLists.length; index++) {
        unorderedLists[index].outerHTML = "
" + unorderedLists[index].outerHTML + "
";
    }
});
<|endoftext|>


<commit_before>'use strict';

module.exports = function (grunt) {
	grunt.registerMultiTask('htmlhintplus', 'Validate html files with htmlhint.', function () {
		var HTMLHint = require("htmlhint").HTMLHint,
			fc = require('file-changed'),
			_ = require('lodash'),
			checkstyleFormatter = require('checkstyle-formatter'),
			fs = require('fs'),
			defaultRules = {
				"tagname-lowercase": true,
				"attr-lowercase": true,
				"attr-value-double-quotes": true,
				"attr-value-not-empty": true,
				"attr-no-duplication": true,
				"doctype-first": true,
				"tag-pair": true,
				"tag-self-close": false,
				"spec-char-escape": true,
				"id-unique": true,
				"src-not-empty": true,
				"head-script-disabled": false,
				"img-alt-require": true,
				"doctype-html5": true,
				"id-class-value": "dash",
				"style-disabled": false,
				"space-tab-mixed-disabled": true,
				"id-class-ad-disabled": true,
				"href-abs-or-rel": true,
				"attr-unsafe-chars": true
			},
			options = this.options(),
			hasError = false,
			customRules = [],
			reducedResults = [],
			extendRules = options.extendRules || false,
			outputTypes = options.output ? (_.isArray(options.output) ? options.output : options.output.split('|')) : ['console'];

		outputTypes = _.map(outputTypes, function (type) {
			return type.toString().toLowerCase();
		});

		if (options.hasOwnProperty('customRules') && typeof options.customRules == 'object') {
			customRules = options.customRules;
		}

		// load custom rules
		if (customRules.length) {
			for (var i = 0, len = customRules.length; i < len; i++) {
				var customRule = require(process.cwd() + '/' + customRules[i]);
				if (typeof customRule == 'function') {
					customRule(HTMLHint);
				} else if (
					typeof customRule == 'object' &&
					customRule.hasOwnProperty('id') &&
					customRule.hasOwnProperty('description') &&
					customRule.hasOwnProperty('init')
				) {
					HTMLHint.addRule(customRule);
				} else {
					console.error("[error]".red.bold, customRules[i].bold, "was invalid and could not be loaded.".red);
				}
			}
		}

		this.files.map(function (files) {
			files.src.map(function (file) {
				if (options.newer && fc.addFile(file).check(file).length === 0) return;

				var text = grunt.file.read(file),
					rules = defaultRules,
					key,
					reg,
					result;

				if (options.ignore) {
					for (key in options.ignore) {
						if (options.ignore.hasOwnProperty(key)) {
							reg = new RegExp(key + '.*?' + options.ignore[key], 'ig');
							text = text.replace(reg, 'x');
						}
					}
				}

				if (options.htmlhintrc) {
					rules = grunt.file.readJSON(options.htmlhintrc);
				} else if (options.rules) {
					if (extendRules) {
						rules = _.extend(defaultRules, options.rules);
					} else {
						rules = options.rules;
					}
				}

				result = HTMLHint.verify(text, rules);
				if ((result.length > 0) && (_.includes(outputTypes, 'default') || _.includes(outputTypes, 'console'))) {
					hasError = true;
					grunt.log.errorlns('HtmlHintPlus: ' + result.length + ' warnings in ' + file + '...');
					result.forEach(function (msg) {
						grunt.log.writeln("[".red + ("L" + msg.line).yellow + ":".red + ("C" + msg.col).yellow + "]".red + ' ' + msg.message.yellow);
					});
				} else {
					if (options.newer) {
						fc.addFile(file).update(file);
					}
					grunt.verbose.ok('HtmlHintPlus: ' + file + ' hint well...');
				}

				// update the reduced results collection with this file's info
				if (_.includes(outputTypes, 'checkstyle') || _.includes(outputTypes, 'json') || _.includes(outputTypes, 'text')) {
					reducedResults.push({
						filename: file,
						messages: _.map(result, function (message) {
							return {
								line: message.line,
								column: message.col,
								severity: message.type,
								message: message.message,
								rule: message.rule.id + ': ' + message.rule.description
							};
						})
					});
				}
			});
		});

		fc.save();

		// make sure that the htmlhint directory exists
		if (_.includes(outputTypes, 'checkstyle') || _.includes(outputTypes, 'json')) {
			try {
				fs.accessSync(process.cwd() + '/htmlhint-report');
			} catch (e) {
				fs.mkdirSync(process.cwd() + '/htmlhint-report');
			}
		}

		// write out the checkstyle file
		if (_.includes(outputTypes, 'checkstyle')) {
			try {
				fs.unlinkSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.xml');
			} catch (e) { }
			try {
				fs.writeFileSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.xml', checkstyleFormatter(reducedResults));
			} catch (e) {
				grunt.log.writeln("Unable to write ".red + "htmlhint-checkstyle-report.xml".white.bold);
			}
		}

		if (_.includes(outputTypes, 'json')) {
			try {
				fs.unlinkSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.json');
			} catch (e) { }
			try {
				fs.writeFileSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.json', JSON.stringify(reducedResults));
			} catch (e) {
				grunt.log.writeln("Unable to write ".red + "htmlhint-checkstyle-report.json".white.bold);
			}
		}

		if (_.includes(outputTypes, 'text')) {
			try {
				fs.unlinkSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.txt');
			} catch (e) { }
			try {
				var textResults = [];
				for (var i = 0, len = reducedResults.length; i < len; i++) {
					textResults.push('HtmlHintPlus: ' + reducedResults[i].messages.length + ' warnings in ' + reducedResults[i].filename + '...');
					textResults.push(_.map(reducedResults[i].messages, function (message) {
						return "[" + ("L" + message.line) + ":" + ("C" + message.column) + "]" + ' ' + message.message;
					}));
				}
				textResults = _.flatten(textResults);
				fs.writeFileSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.txt', textResults.join('\n'));
			} catch (e) {
				grunt.log.writeln("Unable to write ".red + "htmlhint-checkstyle-report.txt".white.bold);
			}
		}

		if (options.force && hasError) {
			grunt.fail.fatal('Can\'t pass htmlhint. Set \'force\' option to continue.');
		}
	});
};
<commit_msg>bugfix: fix test case<commit_after>'use strict';

module.exports = function (grunt) {
	grunt.registerMultiTask('htmlhintplus', 'Validate html files with htmlhint.', function () {
		let
			fs = require('fs'),
			HTMLHint = require("htmlhint").HTMLHint,
			Fc = require('file-changed'),
			_ = require('lodash'),
			checkstyleFormatter = require('checkstyle-formatter'),
			defaultRules = {
				"tagname-lowercase": true,
				"attr-lowercase": true,
				"attr-value-double-quotes": true,
				"attr-value-not-empty": true,
				"attr-no-duplication": true,
				"doctype-first": true,
				"tag-pair": true,
				"tag-self-close": false,
				"spec-char-escape": true,
				"id-unique": true,
				"src-not-empty": true,
				"head-script-disabled": false,
				"img-alt-require": true,
				"doctype-html5": true,
				"id-class-value": "dash",
				"style-disabled": false,
				"space-tab-mixed-disabled": true,
				"id-class-ad-disabled": true,
				"href-abs-or-rel": true,
				"attr-unsafe-chars": true
			},
			options = this.options(),
			hasError = false,
			customRules = [],
			reducedResults = [],
			extendRules = options.extendRules || false,
			outputTypes = options.output ? (_.isArray(options.output) ? options.output : options.output.split('|')) : ['console'],
			fc = new Fc();

		outputTypes = _.map(outputTypes, function (type) {
			return type.toString().toLowerCase();
		});

		if (options.hasOwnProperty('customRules') && typeof options.customRules == 'object') {
			customRules = options.customRules;
		}

		// load custom rules
		if (customRules.length) {
			for (var i = 0, len = customRules.length; i < len; i++) {
				var customRule = require(process.cwd() + '/' + customRules[i]);
				if (typeof customRule == 'function') {
					customRule(HTMLHint);
				} else if (
					typeof customRule == 'object' &&
					customRule.hasOwnProperty('id') &&
					customRule.hasOwnProperty('description') &&
					customRule.hasOwnProperty('init')
				) {
					HTMLHint.addRule(customRule);
				} else {
					console.error("[error]".red.bold, customRules[i].bold, "was invalid and could not be loaded.".red);
				}
			}
		}

		this.files.map(function (files) {
			files.src.map(function (file) {
				if (options.newer && fc.addFile(file).check(file).length === 0) return;

				var text = grunt.file.read(file),
					rules = defaultRules,
					key,
					reg,
					result;

				if (options.ignore) {
					for (key in options.ignore) {
						if (options.ignore.hasOwnProperty(key)) {
							reg = new RegExp(key + '.*?' + options.ignore[key], 'ig');
							text = text.replace(reg, 'x');
						}
					}
				}

				if (options.htmlhintrc) {
					rules = grunt.file.readJSON(options.htmlhintrc);
				} else if (options.rules) {
					if (extendRules) {
						rules = _.extend(defaultRules, options.rules);
					} else {
						rules = options.rules;
					}
				}

				result = HTMLHint.verify(text, rules);
				if ((result.length > 0) && (_.includes(outputTypes, 'default') || _.includes(outputTypes, 'console'))) {
					hasError = true;
					grunt.log.errorlns('HtmlHintPlus: ' + result.length + ' warnings in ' + file + '...');
					result.forEach(function (msg) {
						grunt.log.writeln("[".red + ("L" + msg.line).yellow + ":".red + ("C" + msg.col).yellow + "]".red + ' ' + msg.message.yellow);
					});
				} else {
					if (options.newer) {
						fc.addFile(file).update(file);
					}
					grunt.verbose.ok('HtmlHintPlus: ' + file + ' hint well...');
				}

				// update the reduced results collection with this file's info
				if (_.includes(outputTypes, 'checkstyle') || _.includes(outputTypes, 'json') || _.includes(outputTypes, 'text')) {
					reducedResults.push({
						filename: file,
						messages: _.map(result, function (message) {
							return {
								line: message.line,
								column: message.col,
								severity: message.type,
								message: message.message,
								rule: message.rule.id + ': ' + message.rule.description
							};
						})
					});
				}
			});
		});

		fc.save();

		// make sure that the htmlhint directory exists
		if (_.includes(outputTypes, 'checkstyle') || _.includes(outputTypes, 'json')) {
			try {
				fs.accessSync(process.cwd() + '/htmlhint-report');
			} catch (e) {
				fs.mkdirSync(process.cwd() + '/htmlhint-report');
			}
		}

		// write out the checkstyle file
		if (_.includes(outputTypes, 'checkstyle')) {
			try {
				fs.unlinkSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.xml');
			} catch (e) { }
			try {
				fs.writeFileSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.xml', checkstyleFormatter(reducedResults));
			} catch (e) {
				grunt.log.writeln("Unable to write ".red + "htmlhint-checkstyle-report.xml".white.bold);
			}
		}

		if (_.includes(outputTypes, 'json')) {
			try {
				fs.unlinkSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.json');
			} catch (e) { }
			try {
				fs.writeFileSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.json', JSON.stringify(reducedResults));
			} catch (e) {
				grunt.log.writeln("Unable to write ".red + "htmlhint-checkstyle-report.json".white.bold);
			}
		}

		if (_.includes(outputTypes, 'text')) {
			try {
				fs.unlinkSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.txt');
			} catch (e) { }
			try {
				var textResults = [];
				for (var i = 0, len = reducedResults.length; i < len; i++) {
					textResults.push('HtmlHintPlus: ' + reducedResults[i].messages.length + ' warnings in ' + reducedResults[i].filename + '...');
					textResults.push(_.map(reducedResults[i].messages, function (message) {
						return "[" + ("L" + message.line) + ":" + ("C" + message.column) + "]" + ' ' + message.message;
					}));
				}
				textResults = _.flatten(textResults);
				fs.writeFileSync(process.cwd() + '/htmlhint-report/htmlhint-checkstyle-report.txt', textResults.join('\n'));
			} catch (e) {
				grunt.log.writeln("Unable to write ".red + "htmlhint-checkstyle-report.txt".white.bold);
			}
		}

		if (options.force && hasError) {
			grunt.fail.fatal('Can\'t pass htmlhint. Set \'force\' option to continue.');
		}
	});
};
<|endoftext|>


<commit_before>/*
 * grunt-i18n-compile
 * http://github.com/stefan-dimitrov/grunt-i18n-compile
 *
 * Copyright (c) 2015 Stefan Dimitrov
 * Licensed under the MIT license.
 */

'use strict';

var _ = require('lodash');

module.exports = function (grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('i18n_compile',
    'Assemble JSON output files from language-merged YAML input files.', function () {

    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      merge: false
    });

    // Iterate over all specified file groups.
    this.files.forEach(function (file) {
      // Read specified files.
      var src = file.src.filter(function (filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function (filepath) {
        // Read YAML file.
        return grunt.file.readYAML(filepath);
      });

      var compiled = compileTranslations(src);

      // Handle options.
      if (options.merge) {
        // Write the (single) destination file.
        grunt.file.write(file.dest, JSON.stringify(compiled));

        // Print a success message.
        grunt.log.writeln('File "' + file.dest + '" created.');

        console.log('file obj:', JSON.stringify(file));

        return;
      }

      // Write the destination files.
      for (var lang in compiled) {
        var fileDest = langFileDest(file, lang);
        grunt.file.write(fileDest, JSON.stringify(compiled[lang]));

        // Print a success message.
        grunt.log.writeln('File "' + fileDest + '" created.');
      }

    });
  });

  function compileTranslations (srcList) {
    var compiled = {};
    var rawJson = {};

    for (var i in srcList) {
      _.merge(rawJson, srcList[i]);
    }

    var result = recurseObject(rawJson);

    // Merge result chains
    for (i = 0; i < result.length; i++) {
      var lang = result[i][0];
      if (!compiled[lang]) {
        compiled[lang] = {};
      }
      _.merge(compiled[lang], result[i][1]);
    }
    return compiled;
  }

  function recurseObject (subObject) {
    var resultList = [];
    for (var property in subObject) {
      // Get the language key and the translation value
      if (_.isString(subObject[property])) {
        resultList.push([property, subObject[property]]);
        continue;
      }

      // Nothing to do here. Just skip over
      if (!_.isPlainObject(subObject[property])) {
        continue;
      }

      // Do deeper and build the result chain
      var result = recurseObject(subObject[property]);
      for (var i = 0; i < result.length; i++) {
        var tmp = {};
        tmp[property] = result[i][1];
        resultList.push([result[i][0], tmp]);
      }
    }

    return resultList;
  }

  function langFileDest (file, lang) {
    var parts = file.dest.split(/([.][^.\/]+$)/i, 2);

    if (parts.length > 1) {
      return parts[0] + lang + parts[1];
    }

    return parts[0] + lang;
  }

};
<commit_msg>Remove forgotten log call.<commit_after>/*
 * grunt-i18n-compile
 * http://github.com/stefan-dimitrov/grunt-i18n-compile
 *
 * Copyright (c) 2015 Stefan Dimitrov
 * Licensed under the MIT license.
 */

'use strict';

var _ = require('lodash');

module.exports = function (grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('i18n_compile',
    'Assemble JSON output files from language-merged YAML input files.', function () {

    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      merge: false
    });

    // Iterate over all specified file groups.
    this.files.forEach(function (file) {
      // Read specified files.
      var src = file.src.filter(function (filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function (filepath) {
        // Read YAML file.
        return grunt.file.readYAML(filepath);
      });

      var compiled = compileTranslations(src);

      // Handle options.
      if (options.merge) {
        // Write the (single) destination file.
        grunt.file.write(file.dest, JSON.stringify(compiled));

        // Print a success message.
        grunt.log.writeln('File "' + file.dest + '" created.');

        return;
      }

      // Write the destination files.
      for (var lang in compiled) {
        var fileDest = langFileDest(file, lang);
        grunt.file.write(fileDest, JSON.stringify(compiled[lang]));

        // Print a success message.
        grunt.log.writeln('File "' + fileDest + '" created.');
      }

    });
  });

  function compileTranslations (srcList) {
    var compiled = {};
    var rawJson = {};

    for (var i in srcList) {
      _.merge(rawJson, srcList[i]);
    }

    var result = recurseObject(rawJson);

    // Merge result chains
    for (i = 0; i < result.length; i++) {
      var lang = result[i][0];
      if (!compiled[lang]) {
        compiled[lang] = {};
      }
      _.merge(compiled[lang], result[i][1]);
    }
    return compiled;
  }

  function recurseObject (subObject) {
    var resultList = [];
    for (var property in subObject) {
      // Get the language key and the translation value
      if (_.isString(subObject[property])) {
        resultList.push([property, subObject[property]]);
        continue;
      }

      // Nothing to do here. Just skip over
      if (!_.isPlainObject(subObject[property])) {
        continue;
      }

      // Do deeper and build the result chain
      var result = recurseObject(subObject[property]);
      for (var i = 0; i < result.length; i++) {
        var tmp = {};
        tmp[property] = result[i][1];
        resultList.push([result[i][0], tmp]);
      }
    }

    return resultList;
  }

  function langFileDest (file, lang) {
    var parts = file.dest.split(/([.][^.\/]+$)/i, 2);

    if (parts.length > 1) {
      return parts[0] + lang + parts[1];
    }

    return parts[0] + lang;
  }

};
<|endoftext|>


<commit_before>/* global Evaporate, evaporateOptions */
;(function (Evaporate, evaporateOptions) {
  'use strict';

  angular
    .module('evaporate', [])

    .factory('eva', [function () {
      return {
        _: new Evaporate(evaporateOptions),
        urlBase: 'http://' + evaporateOptions.bucket + '.s3.amazonaws.com/'
      };
    }])

    .directive('evaporate', ['eva', function (eva) {

      function link (scope, element, attrs) {

        // allocate eva's data
        if (!scope.data) scope.data = {};

        var data = scope.data,
            foo = function () {},

            // apply defaults for input parameters
            dir = data.dir ? (data.dir + '/') : '',
            headersCommon = data.headersCommon || {},
            headersSigned = data.headersSigned || {},
            onFileProgress = (typeof data.onFileProgress === 'function' ? data.onFileProgress : foo),
            onFileComplete = (typeof data.onFileComplete === 'function' ? data.onFileComplete : foo);

        // expose some info for parent scope
        data.ready = false;
        data.files = [];

        // ready..
        if (eva._.supported) {

          // ..steady..
          element.bind('change', function (event) {

            // process added files
            angular.forEach(event.target.files, function (file) {

              // process file attrs
              file.started = Date.now();
              file.path = dir + file.started + '$' + file.name;
              file.url = eva.urlBase + file.path;

              // queue file for upload
              eva._.add({

                // filename, relative to bucket
                name: file.path,

                // content
                file: file,

                // headers
                contentType: file.type || 'binary/octet-stream',
                notSignedHeadersAtInitiate: headersCommon,
                xAmzHeadersAtInitiate:      headersSigned,

                // event callbacks
                complete: function () {

                  // check file as completed
                  file.completed = true;

                  // execute user's callback
                  onFileComplete(file);

                  // update ui
                  scope.$apply();
                },
                progress: function (progress) {

                  // update progress
                  file.progress = Math.round(progress * 10000) / 100;
                  file.timeLeft = Math.round(
                    (100 - file.progress) / file.progress *
                    (Date.now() - file.started) / 1000
                  );

                  // execute user's callback
                  onFileProgress(file);

                  // update ui
                  scope.$apply();
                }
              });

              // expose file data to model
              data.files.push(file);
            });

            // update ui
            scope.$apply();
          });

          // ..go!
          data.ready = true;
        }
      }

      return {
        restrict: 'A',
        link: link,
        scope: {
          data: '=evaModel'
        }
      };
    }]);

})(Evaporate, evaporateOptions);
<commit_msg>rename file.path into file.path_ to please firefox<commit_after>/* global Evaporate, evaporateOptions */
;(function (Evaporate, evaporateOptions) {
  'use strict';

  angular
    .module('evaporate', [])

    .factory('eva', [function () {
      return {
        _: new Evaporate(evaporateOptions),
        urlBase: 'http://' + evaporateOptions.bucket + '.s3.amazonaws.com/'
      };
    }])

    .directive('evaporate', ['eva', function (eva) {

      function link (scope, element, attrs) {

        // allocate eva's data
        if (!scope.data) scope.data = {};

        var data = scope.data,
            foo = function () {},

            // apply defaults for input parameters
            dir = data.dir ? (data.dir + '/') : '',
            headersCommon = data.headersCommon || {},
            headersSigned = data.headersSigned || {},
            onFileProgress = (typeof data.onFileProgress === 'function' ? data.onFileProgress : foo),
            onFileComplete = (typeof data.onFileComplete === 'function' ? data.onFileComplete : foo);

        // expose some info for parent scope
        data.ready = false;
        data.files = [];

        // ready..
        if (eva._.supported) {

          // ..steady..
          element.bind('change', function (event) {

            // process added files
            angular.forEach(event.target.files, function (file) {

              // process file attrs
              file.started = Date.now();
              file.path_ = dir + file.started + '$' + file.name;
              file.url = eva.urlBase + file.path_;

              // queue file for upload
              eva._.add({

                // filename, relative to bucket
                name: file.path_,

                // content
                file: file,

                // headers
                contentType: file.type || 'binary/octet-stream',
                notSignedHeadersAtInitiate: headersCommon,
                xAmzHeadersAtInitiate:      headersSigned,

                // event callbacks
                complete: function () {

                  // check file as completed
                  file.completed = true;

                  // execute user's callback
                  onFileComplete(file);

                  // update ui
                  scope.$apply();
                },
                progress: function (progress) {

                  // update progress
                  file.progress = Math.round(progress * 10000) / 100;
                  file.timeLeft = Math.round(
                    (100 - file.progress) / file.progress *
                    (Date.now() - file.started) / 1000
                  );

                  // execute user's callback
                  onFileProgress(file);

                  // update ui
                  scope.$apply();
                }
              });

              // expose file data to model
              data.files.push(file);
            });

            // update ui
            scope.$apply();
          });

          // ..go!
          data.ready = true;
        }
      }

      return {
        restrict: 'A',
        link: link,
        scope: {
          data: '=evaModel'
        }
      };
    }]);

})(Evaporate, evaporateOptions);
<|endoftext|>


<commit_before>const joi = require('joi');

const entrySchema = joi.object({
    op: joi.string().valid('restore', 'delete', 'archive').required(),
    bucketName: joi.string().required(),
    objectKey: joi.string().required(),
    objectVersion: joi.string(),
    accountId: joi.string().required(),
    archiveInfo: joi.object().required(),
    requestId: joi.string().required(),
});

class ColdStorageStatusQueueEntry {
    static createFromKafkaEntry(kafkaEntry) {
        try {
            const res = entrySchema.validate(JSON.parse(kafkaEntry.value));

            if (res.error) {
                return {
                    error: {
                        message: 'invalid status kafka entry',
                        description: res.error,
                    },
                };
            }

            const action = new ColdStorageStatusQueueEntry(res.value);
            return action;
        } catch (err) {
            return { error: { message: 'malformed JSON in kafka entry',
                              description: err.message } };
        }
    }

    constructor(attributes) {
        this._attributes = attributes;
    }

    get op() {
        return this._attributes.op;
    }

    get archiveInfo() {
        return this._attributes.archiveInfo;
    }

    get requestId() {
        return this._attributes.requestId;
    }

    get target() {
        return {
            bucketName: this._attributes.bucketName,
            objectKey: this._attributes.objectKey,
            objectVersion: this._attributes.objectVersion,
            accountId: this._attributes.accountId,
        };
    }

    /**
     * Get a JS object suitable for logging useful info about the action
     *
     * @return {object} object containing attributes to be logged
     */
    getLogInfo() {
        return {
            op: this._attributes.op,
            requestId: this._attributes.requestId,
        };
    }
}

module.exports = ColdStorageStatusQueueEntry;
<commit_msg>BB-240: support more fields in sorbet messages<commit_after>const joi = require('joi');

const entrySchema = joi.object({
    op: joi.string().valid('restore', 'delete', 'archive').required(),
    bucketName: joi.string().required(),
    objectKey: joi.string().required(),
    objectVersion: joi.string().optional(),
    accountId: joi.string().required(),
    archiveInfo: joi.object().required(),
    requestId: joi.string().required(),

    originalMessage: joi.object(),
    reason: joi.optional(),
    date: joi.date().optional(),
}).unknown(true);

class ColdStorageStatusQueueEntry {
    static createFromKafkaEntry(kafkaEntry) {
        try {
            const res = entrySchema.validate(JSON.parse(kafkaEntry.value));

            if (res.error) {
                return {
                    error: {
                        message: 'invalid status kafka entry',
                        description: res.error,
                    },
                };
            }

            const action = new ColdStorageStatusQueueEntry(res.value);
            return action;
        } catch (err) {
            return { error: { message: 'malformed JSON in kafka entry',
                              description: err.message } };
        }
    }

    constructor(attributes) {
        this._attributes = attributes;
    }

    get op() {
        return this._attributes.op;
    }

    get archiveInfo() {
        return this._attributes.archiveInfo;
    }

    get requestId() {
        return this._attributes.requestId;
    }

    get target() {
        return {
            bucketName: this._attributes.bucketName,
            objectKey: this._attributes.objectKey,
            objectVersion: this._attributes.objectVersion,
            accountId: this._attributes.accountId,
        };
    }

    /**
     * Get a JS object suitable for logging useful info about the action
     *
     * @return {object} object containing attributes to be logged
     */
    getLogInfo() {
        return {
            op: this._attributes.op,
            requestId: this._attributes.requestId,
        };
    }
}

module.exports = ColdStorageStatusQueueEntry;
<|endoftext|>


<commit_before>// authors: <martind,fredrik>@last.fm
// Wed Apr  8 13:37:09 UTC 2009

// data source.
var wsUrl = 'http://localhost:8086/data/';

var chartWidth = 600;
var chartHeight = 300;
var numXTicks = chartWidth / 80; // one tick every 80 pixels

// from http://beta.dailycolorscheme.com/archive/2006/09/07
var chartWidth = 600;
var chartHeight = 300;
var numXTicks = chartWidth / 80; // one tick every 80 pixels
var graphStyles = new Array(
			    "2B6088", // blue1
			    //"0A55A3", // blue2
			    //"006EBA", // blue3
			    //"8D1C0C", // red1
			    "3EA63B", // green
			    "FF6D06", // orange
			    "FD1B15", // red2
			    "FFE812", // yellow
			    "808080"  // gray
			    );
var missingValue = '_';

// fills the form with values from the GET-request,
// falling back on the defaults.
function updateForm() {
    var fields = ["t0", "t1", "unit", "d0", "d0v", "d1", "d1v", "d2", "d2v", "d3", "d3v", "d4", "d4v"];
    var defaults = {'t0':'20090101', 't1':'20090331', 'unit':'pageviews', 'd0':'country', 'd0v':'US,DE,SE'}
    $.each(fields, function(i, item) {
	    $("input#"+item).val(urldecode($(document).getUrlParam(item, defaults[item])))
		});
}

// draws the graph.
function updateGraph() {
    loadData(
	     $('#graphNav input[name=t0]')[0].value,
	     $('#graphNav input[name=t1]')[0].value,
	     $('#graphNav input[name=unit]')[0].value,
	     $('#graphNav input[name=d0]')[0].value,
	     $('#graphNav input[name=d0v]')[0].value,
	     dictToString(loadFilters()));
}

// create query string from dictionary of values.
function dictToString(ary) {
    var s = "";
    $.each(ary, function(a) {
	    if (ary[a] != "") {
		s += a;
		s += "=";
		s += ary[a];
		s += "&";
	    }
    });
    return s;
}

// construct dictionary from dimension fields.
// TODO: fix this up to not be so pre-defined.
function loadFilters() {
    // highly hardcoded.
    d1  = $('input#d1').val(); // and so on..
    d1v = $('#graphNav input[name=d1v]')[0].value;
    d2  = $('#graphNav input[name=d2]')[0].value;
    d2v = $('#graphNav input[name=d2v]')[0].value;
    d3  = $('#graphNav input[name=d3]')[0].value;
    d3v = $('#graphNav input[name=d3v]')[0].value;
    d4  = $('#graphNav input[name=d4]')[0].value;
    d4v = $('#graphNav input[name=d4v]')[0].value;
    return {'d1':d1, 'd1v':d1v, 'd2':d2, 'd2v':d2v, 'd3':d3, 'd3v':d3v, 'd4':d4, 'd4v':d4v};
}

// callback for the json data.
function jsonZohmgFeed(data) {
    graph = pivot(data);
    var imgUrl = chartImgUrl(graph);
    $('#graph').html('');
    $('#undergraph').append(' and chart.');
}

function loadData(t0, t1, unit, d0, d0v, filters) {
    var dataUrl = wsUrl +
	'?t0=' + encodeURIComponent(t0) +
	'&t1=' + encodeURIComponent(t1) +
	'&unit=' + encodeURIComponent(unit) +
	'&d0=' + encodeURIComponent(d0) +
	'&d0v=' + encodeURIComponent(d0v) +
	'&' + filters +
	'&jsoncallback=?';

    $('#undergraph').html('raw data');

    $.getJSON(dataUrl); // magically calls jsonZohmgFeed() as callback.
}

// construct a google charts url.
function chartImgUrl(graph) {
    // axis legends: strings, limited to numXTicks entries
    var chxl = '0:|';
    for (var idx=0; idx<numXTicks; idx++) {
	var label = graph.legend[Math.round(idx * (graph.legend.length-1) / numXTicks)];
	chxl += label + '|';
    }
    // axis legends: ranges
    var chxr = '1,' +
	graph.minValue + ',' +
	graph.maxValue;

    // item chart data, labels + colours
    var series = new Array();
    var labels = new Array();
    var colours = new Array();
    var colIdx = 0;
    $.each(graph.lines, function(label, line) {
	    //series.push(line.join(',')); // text encoding
	    series.push(simpleEncode(line, graph.maxValue));
	    //alert(simpleEncode(line, graph.maxValue));
	    labels.push(label);
	    colours.push(graphStyles[colIdx++]);
	});
    var chd = 's:' + series.join(',');
    var chdl = labels.join('|');
    var chco = colours.join(',');

    return 'http://chart.apis.google.com/chart?' +
	'chs=' + chartWidth + 'x' + chartHeight +          // size
	'&cht=lc' +            // type
	'&chds=' + graph.minValue + ',' + graph.maxValue + // data scaling
	'&chd=' + chd +        // data
	'&chco=' + chco +      // colour
	'&chdl=' + chdl +      // data labels
	'&chxt=x,y' +          // axes
	'&chxl=' + chxl +      // axis labels
	'&chxr=' + chxr +      // axis ranges
	'&chxs=0,,12,-1,lt' +  // axis styles
	'';
}

// Transforms the input data into a data structure
// better suited for graphing. Detects missing values
// for each time series.
function pivot(data) {
    graph = {
	legend: [],
	lines: {},
	minValue: 0,
	maxValue: 0
    };
    var numRows = 0;

    // get list of all dates, so we can guarantee sort order
    // get list of all items, so we can detect gaps in their time series
    var dates = new Array();
    var items = new Array();
    var actual_data = new Array();
    $.each(data, function(index, d) {
	    $.each(d, function(date,row) {
		    if (date!=0) { dates.push(date); } // not sure why we always get a 0 as last date
		    actual_data[date] = row;
		    $.each(row, function(item,value){
			    if ($.inArray(item, items) == -1) {
				items.push(item);
				if (!graph.lines[item]) {
				    graph.lines[item] = new Array();
				}
			    }
			});
		});
	});

    dates.sort();

    // build graph
    $.each(dates, function(idx, date){
	    var row = actual_data[date];
	    graph.legend.push(date);
	    $.each(items, function(idx,item) {
		    var value = row[item];
		    if (!value) {
			graph.lines[item].push(missingValue);
		    }
		    else {
			graph.minValue = Math.min(graph.minValue, value);
			graph.maxValue = Math.max(graph.maxValue, value);
			graph.lines[item].push(value);
		    }
		});
	    numRows++;
	});
    return graph;
}

// modified from http://code.google.com/apis/chart/formats.html
var simpleEncoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function simpleEncode(valueArray,maxValue) {
    var chartData = [];
    for (var i = 0; i < valueArray.length; i++) {
	var currentValue = valueArray[i];
	if (!isNaN(currentValue) && currentValue >= 0) {
	    chartData.push(simpleEncoding.charAt(Math.round((simpleEncoding.length-1) * currentValue / maxValue)));
	}
	else {
	    chartData.push('_');
	}
    }
    return chartData.join('');
}

// snatched from http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_urldecode/
function urldecode( str ) {
    // http://kevin.vanzonneveld.net

    if (str === undefined || str == null) { return undefined; }

    var histogram = {};
    var ret = str.toString();

    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };

    // The histogram is identical to the one in urlencode.
    histogram["'"]   = '%27';
    histogram['(']   = '%28';
    histogram[')']   = '%29';
    histogram['*']   = '%2A';
    histogram['~']   = '%7E';
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    histogram['\u20AC'] = '%80';
    histogram['\u0081'] = '%81';
    histogram['\u201A'] = '%82';
    histogram['\u0192'] = '%83';
    histogram['\u201E'] = '%84';
    histogram['\u2026'] = '%85';
    histogram['\u2020'] = '%86';
    histogram['\u2021'] = '%87';
    histogram['\u02C6'] = '%88';
    histogram['\u2030'] = '%89';
    histogram['\u0160'] = '%8A';
    histogram['\u2039'] = '%8B';
    histogram['\u0152'] = '%8C';
    histogram['\u008D'] = '%8D';
    histogram['\u017D'] = '%8E';
    histogram['\u008F'] = '%8F';
    histogram['\u0090'] = '%90';
    histogram['\u2018'] = '%91';
    histogram['\u2019'] = '%92';
    histogram['\u201C'] = '%93';
    histogram['\u201D'] = '%94';
    histogram['\u2022'] = '%95';
    histogram['\u2013'] = '%96';
    histogram['\u2014'] = '%97';
    histogram['\u02DC'] = '%98';
    histogram['\u2122'] = '%99';
    histogram['\u0161'] = '%9A';
    histogram['\u203A'] = '%9B';
    histogram['\u0153'] = '%9C';
    histogram['\u009D'] = '%9D';
    histogram['\u017E'] = '%9E';
    histogram['\u0178'] = '%9F';

    for (replace in histogram) {
        search = histogram[replace]; // Switch order when decoding
        ret = replacer(search, replace, ret) // Custom replace. No regexing
    }

    // End with decodeURIComponent, which most resembles PHP's encoding functions
    ret = decodeURIComponent(ret);

    return ret;
}
<commit_msg>static-skeleton/js/zohmg.js: added ASF header.<commit_after>// authors: <martind,fredrik>@last.fm
// Wed Apr  8 13:37:09 UTC 2009

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

// data source.
var wsUrl = 'http://localhost:8086/data/';

var chartWidth = 600;
var chartHeight = 300;
var numXTicks = chartWidth / 80; // one tick every 80 pixels

// from http://beta.dailycolorscheme.com/archive/2006/09/07
var chartWidth = 600;
var chartHeight = 300;
var numXTicks = chartWidth / 80; // one tick every 80 pixels
var graphStyles = new Array(
			    "2B6088", // blue1
			    //"0A55A3", // blue2
			    //"006EBA", // blue3
			    //"8D1C0C", // red1
			    "3EA63B", // green
			    "FF6D06", // orange
			    "FD1B15", // red2
			    "FFE812", // yellow
			    "808080"  // gray
			    );
var missingValue = '_';

// fills the form with values from the GET-request,
// falling back on the defaults.
function updateForm() {
    var fields = ["t0", "t1", "unit", "d0", "d0v", "d1", "d1v", "d2", "d2v", "d3", "d3v", "d4", "d4v"];
    var defaults = {'t0':'20090101', 't1':'20090331', 'unit':'pageviews', 'd0':'country', 'd0v':'US,DE,SE'}
    $.each(fields, function(i, item) {
	    $("input#"+item).val(urldecode($(document).getUrlParam(item, defaults[item])))
		});
}

// draws the graph.
function updateGraph() {
    loadData(
	     $('#graphNav input[name=t0]')[0].value,
	     $('#graphNav input[name=t1]')[0].value,
	     $('#graphNav input[name=unit]')[0].value,
	     $('#graphNav input[name=d0]')[0].value,
	     $('#graphNav input[name=d0v]')[0].value,
	     dictToString(loadFilters()));
}

// create query string from dictionary of values.
function dictToString(ary) {
    var s = "";
    $.each(ary, function(a) {
	    if (ary[a] != "") {
		s += a;
		s += "=";
		s += ary[a];
		s += "&";
	    }
    });
    return s;
}

// construct dictionary from dimension fields.
// TODO: fix this up to not be so pre-defined.
function loadFilters() {
    // highly hardcoded.
    d1  = $('input#d1').val(); // and so on..
    d1v = $('#graphNav input[name=d1v]')[0].value;
    d2  = $('#graphNav input[name=d2]')[0].value;
    d2v = $('#graphNav input[name=d2v]')[0].value;
    d3  = $('#graphNav input[name=d3]')[0].value;
    d3v = $('#graphNav input[name=d3v]')[0].value;
    d4  = $('#graphNav input[name=d4]')[0].value;
    d4v = $('#graphNav input[name=d4v]')[0].value;
    return {'d1':d1, 'd1v':d1v, 'd2':d2, 'd2v':d2v, 'd3':d3, 'd3v':d3v, 'd4':d4, 'd4v':d4v};
}

// callback for the json data.
function jsonZohmgFeed(data) {
    graph = pivot(data);
    var imgUrl = chartImgUrl(graph);
    $('#graph').html('');
    $('#undergraph').append(' and chart.');
}

function loadData(t0, t1, unit, d0, d0v, filters) {
    var dataUrl = wsUrl +
	'?t0=' + encodeURIComponent(t0) +
	'&t1=' + encodeURIComponent(t1) +
	'&unit=' + encodeURIComponent(unit) +
	'&d0=' + encodeURIComponent(d0) +
	'&d0v=' + encodeURIComponent(d0v) +
	'&' + filters +
	'&jsoncallback=?';

    $('#undergraph').html('raw data');

    $.getJSON(dataUrl); // magically calls jsonZohmgFeed() as callback.
}

// construct a google charts url.
function chartImgUrl(graph) {
    // axis legends: strings, limited to numXTicks entries
    var chxl = '0:|';
    for (var idx=0; idx<numXTicks; idx++) {
	var label = graph.legend[Math.round(idx * (graph.legend.length-1) / numXTicks)];
	chxl += label + '|';
    }
    // axis legends: ranges
    var chxr = '1,' +
	graph.minValue + ',' +
	graph.maxValue;

    // item chart data, labels + colours
    var series = new Array();
    var labels = new Array();
    var colours = new Array();
    var colIdx = 0;
    $.each(graph.lines, function(label, line) {
	    //series.push(line.join(',')); // text encoding
	    series.push(simpleEncode(line, graph.maxValue));
	    //alert(simpleEncode(line, graph.maxValue));
	    labels.push(label);
	    colours.push(graphStyles[colIdx++]);
	});
    var chd = 's:' + series.join(',');
    var chdl = labels.join('|');
    var chco = colours.join(',');

    return 'http://chart.apis.google.com/chart?' +
	'chs=' + chartWidth + 'x' + chartHeight +          // size
	'&cht=lc' +            // type
	'&chds=' + graph.minValue + ',' + graph.maxValue + // data scaling
	'&chd=' + chd +        // data
	'&chco=' + chco +      // colour
	'&chdl=' + chdl +      // data labels
	'&chxt=x,y' +          // axes
	'&chxl=' + chxl +      // axis labels
	'&chxr=' + chxr +      // axis ranges
	'&chxs=0,,12,-1,lt' +  // axis styles
	'';
}

// Transforms the input data into a data structure
// better suited for graphing. Detects missing values
// for each time series.
function pivot(data) {
    graph = {
	legend: [],
	lines: {},
	minValue: 0,
	maxValue: 0
    };
    var numRows = 0;

    // get list of all dates, so we can guarantee sort order
    // get list of all items, so we can detect gaps in their time series
    var dates = new Array();
    var items = new Array();
    var actual_data = new Array();
    $.each(data, function(index, d) {
	    $.each(d, function(date,row) {
		    if (date!=0) { dates.push(date); } // not sure why we always get a 0 as last date
		    actual_data[date] = row;
		    $.each(row, function(item,value){
			    if ($.inArray(item, items) == -1) {
				items.push(item);
				if (!graph.lines[item]) {
				    graph.lines[item] = new Array();
				}
			    }
			});
		});
	});

    dates.sort();

    // build graph
    $.each(dates, function(idx, date){
	    var row = actual_data[date];
	    graph.legend.push(date);
	    $.each(items, function(idx,item) {
		    var value = row[item];
		    if (!value) {
			graph.lines[item].push(missingValue);
		    }
		    else {
			graph.minValue = Math.min(graph.minValue, value);
			graph.maxValue = Math.max(graph.maxValue, value);
			graph.lines[item].push(value);
		    }
		});
	    numRows++;
	});
    return graph;
}

// modified from http://code.google.com/apis/chart/formats.html
var simpleEncoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function simpleEncode(valueArray,maxValue) {
    var chartData = [];
    for (var i = 0; i < valueArray.length; i++) {
	var currentValue = valueArray[i];
	if (!isNaN(currentValue) && currentValue >= 0) {
	    chartData.push(simpleEncoding.charAt(Math.round((simpleEncoding.length-1) * currentValue / maxValue)));
	}
	else {
	    chartData.push('_');
	}
    }
    return chartData.join('');
}

// snatched from http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_urldecode/
function urldecode( str ) {
    // http://kevin.vanzonneveld.net

    if (str === undefined || str == null) { return undefined; }

    var histogram = {};
    var ret = str.toString();

    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };

    // The histogram is identical to the one in urlencode.
    histogram["'"]   = '%27';
    histogram['(']   = '%28';
    histogram[')']   = '%29';
    histogram['*']   = '%2A';
    histogram['~']   = '%7E';
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    histogram['\u20AC'] = '%80';
    histogram['\u0081'] = '%81';
    histogram['\u201A'] = '%82';
    histogram['\u0192'] = '%83';
    histogram['\u201E'] = '%84';
    histogram['\u2026'] = '%85';
    histogram['\u2020'] = '%86';
    histogram['\u2021'] = '%87';
    histogram['\u02C6'] = '%88';
    histogram['\u2030'] = '%89';
    histogram['\u0160'] = '%8A';
    histogram['\u2039'] = '%8B';
    histogram['\u0152'] = '%8C';
    histogram['\u008D'] = '%8D';
    histogram['\u017D'] = '%8E';
    histogram['\u008F'] = '%8F';
    histogram['\u0090'] = '%90';
    histogram['\u2018'] = '%91';
    histogram['\u2019'] = '%92';
    histogram['\u201C'] = '%93';
    histogram['\u201D'] = '%94';
    histogram['\u2022'] = '%95';
    histogram['\u2013'] = '%96';
    histogram['\u2014'] = '%97';
    histogram['\u02DC'] = '%98';
    histogram['\u2122'] = '%99';
    histogram['\u0161'] = '%9A';
    histogram['\u203A'] = '%9B';
    histogram['\u0153'] = '%9C';
    histogram['\u009D'] = '%9D';
    histogram['\u017E'] = '%9E';
    histogram['\u0178'] = '%9F';

    for (replace in histogram) {
        search = histogram[replace]; // Switch order when decoding
        ret = replacer(search, replace, ret) // Custom replace. No regexing
    }

    // End with decodeURIComponent, which most resembles PHP's encoding functions
    ret = decodeURIComponent(ret);

    return ret;
}
<|endoftext|>


<commit_before>module.exports = {
    cookieSecret: 'dummy',
    addsol: {
      host: '185.82.86.101',
      port: '9009',
      id: 'AS',
      pass: 'iHDRxTeZzQqgFzZclj2D',
    }
};
<commit_msg>Revert "IP address"<commit_after>module.exports = {
    cookieSecret: ' ',
    addsol: {
      host: 'localhost',
      port: '9009',
      id: 'AS',
      pass: 'iHDRxTeZzQqgFzZclj2D',
    }
};
<|endoftext|>


<commit_before>'use strict';

var Promise      = require('bluebird');
var Handlebars   = require('handlebars');
var Notification = require('../../api/models/Notification');

var Users = require('../../api/collections/Users');
var users = new Users();

module.exports = function(router, resources) {
	resources.actions.notify = function(conn, project, options) {
		var roleIds = options.role_ids || [];

		// get all project assignments
		return Promise.all(Object.keys(project.assignments.data).map(function(userId) {
			var assignment = project.assignments.data[userId];

			// only notify specified roles
			if(roleIds.indexOf(assignment.role_id) === -1)
				return;

			// create a notification
			return Notification.create(conn, {
				user_id: userId,
				subject: options.subject,

				// TODO: first pull user from db to get name, etc
				content: Handlebars.compile(options.template || '')({ project: project, cycle: project.cycle })
			}, true)

			.then(function(notification){
				return users.get(conn, notification.user_id, true)

				// email recovery token to user
				.then(function(user){
					return resources.mail({
						to: user.email,
						subject: notification.subject,
						html: notification.content
					});
				});
			});
		}));
	};
};
<commit_msg>Send triggered emails in the background<commit_after>'use strict';

var Promise      = require('bluebird');
var Handlebars   = require('handlebars');
var Notification = require('../../api/models/Notification');

var Users = require('../../api/collections/Users');
var users = new Users();

module.exports = function(router, resources) {
	resources.actions.notify = function(conn, project, options) {
		var roleIds = options.role_ids || [];

		// get all project assignments
		return Promise.settle(Object.keys(project.assignments.data).map(function(userId) {
			var assignment = project.assignments.data[userId];

			// only notify specified roles
			if(roleIds.indexOf(assignment.role_id) === -1)
				return;

			// create a notification
			return Notification.create(conn, {
				user_id: userId,
				subject: options.subject,

				// TODO: first pull user from db to get name, etc
				content: Handlebars.compile(options.template || '')({ project: project, cycle: project.cycle })
			}, true)

			.then(function(notification){
				return users.get(conn, notification.user_id, true)
				.then(function(user){

					// send mail in the background
					resources.mail({
						to: user.email,
						subject: notification.subject,
						html: notification.content
					});

				});
			});
		}));
	};
};
<|endoftext|>


<commit_before>/*
 * grunt-flaticon
 *
 * Copyright (c) 2015 Marcin Bonk, Bronisław Białek
 * Licensed under the MIT license.
 */

module.exports = (function () {
    'use strict';

    var needle = require('needle');
    var unzip = require('unzip');
    var fs = require('fs');
    var path = require('path');
    var grunt = require('grunt');

    function flaticon(options) {
        this.options = options;
        this.config = typeof options.config === "string" ? grunt.file.readJSON(options.config) : options.config;
    }

    flaticon.prototype.downloadZip = function downloadZip(done) {
        var data = {data: JSON.stringify(this.config.icons), acc: "font", scode: "4", uId: 0};

        needle.post(this.options.url, data, {multipart: true}, function (err, res, body) {
            if (err) {
                grunt.verbose.writeln('fetching error: ' + err);
                done();
            } else {
                grunt.verbose.writeln('sid: ' + body);
                this.handlePackageHash(body, done);
            }
        }.bind(this));
    };

    flaticon.prototype.handlePackageHash = function handlePackageHash(id, done) {
        grunt.log.write('Fetching archive ' + this.options.url_package + id + '...');

        var request = needle.get(this.options.url_package + id, function (err, res, body) {
            if (err) {
                done();
                grunt.log.err();
            }
        });

        request.pipe(unzip.Parse())

            .on('entry', function (entry) {
                var ext = path.extname(entry.path);
            if (entry.type === 'File') {
                switch (ext) {
                    case '.woff':case '.svg': case '.ttf': case '.eot':
                        var fontPath = path.join(this.options.fonts, path.basename(entry.path));
                        return entry.pipe(fs.createWriteStream(fontPath));

                    case '.css':
                        if (!this.options.use_package_css) {
                            var fontPath = path.join(this.options.styles, path.basename(entry.path));
                            return entry.pipe(fs.createWriteStream(fontPath));
                        }

                        default:
                            grunt.verbose.writeln('Ignored ', entry.path);
                            entry.autodrain();
                    }
                }
            }.bind(this))
        .on('finish', function() {
            if (!this.options.use_package_css) {
                this.generateCSS();
            }

            grunt.log.ok();
            done();
        }.bind(this));

    };

    flaticon.prototype.generateCSS = function generateCSS() {
        var file = grunt.file.read(__dirname + '/../../templates/flaticon.css');
        var template = grunt.template.process(file, {data: this.config});
        return template;
    };

    return flaticon;
})();<commit_msg>generating css done<commit_after>/*
 * grunt-flaticon
 *
 * Copyright (c) 2015 Marcin Bonk, Bronisław Białek
 * Licensed under the MIT license.
 */

module.exports = (function () {
    'use strict';

    var needle = require('needle');
    var unzip = require('unzip');
    var fs = require('fs');
    var path = require('path');
    var grunt = require('grunt');

    /**
     * @param options
     */
    function flaticon(options) {
        this.options = options;
        this.config = typeof options.config === "string" ? grunt.file.readJSON(options.config) : options.config;
    }

    /**
     * @param done
     */
    flaticon.prototype.downloadZip = function downloadZip(done) {
        var data = {data: JSON.stringify(this.config.icons), acc: "font", scode: "4", uId: 0};

        needle.post(this.options.url, data, {multipart: true}, function (err, res, body) {
            if (err) {
                grunt.verbose.writeln('fetching error: ' + err);
                done();
            } else {
                grunt.verbose.writeln('sid: ' + body);
                this.handlePackageHash(body, done);
            }
        }.bind(this));
    };

    /**
     * @param id
     * @param done
     */
    flaticon.prototype.handlePackageHash = function handlePackageHash(id, done) {
        grunt.log.write('Fetching archive ' + this.options.url_package + id + '...');

        var request = needle.get(this.options.url_package + id, function (err, res, body) {
            if (err) {
                done();
                grunt.log.err();
            }
        });

        request.pipe(unzip.Parse())

            .on('entry', function (entry) {
                var ext = path.extname(entry.path);
                if (entry.type === 'File') {
                    switch (ext) {
                        case '.woff':
                        case '.svg':
                        case '.ttf':
                        case '.eot':
                            var fontPath = path.join(this.options.fonts, path.basename(entry.path));
                            return entry.pipe(fs.createWriteStream(fontPath));

                        case '.css':
                            if (!this.options.use_package_css) {
                                var fontPath = path.join(this.options.styles, path.basename(entry.path));
                                return entry.pipe(fs.createWriteStream(fontPath));
                            }

                        default:
                            grunt.verbose.writeln('Ignored ', entry.path);
                            entry.autodrain();
                    }
                }
            }.bind(this))
            .on('finish', function () {
                if (!this.options.use_package_css) {
                    var templateContent = this.generateCSS();
                    var templatePath = path.join(this.options.styles, 'flaticon.css');
                    grunt.file.write(templatePath, templateContent);
                }

                grunt.log.ok();
                done();
            }.bind(this));

    };

    /**
     * @returns {*|void}
     */
    flaticon.prototype.generateCSS = function generateCSS() {
        var file = grunt.file.read(__dirname + '/../../templates/flaticon.css');
        var template = grunt.template.process(file, {data: this.config});
        return template;
    };

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


<commit_before>define(["jquery", "config", "webix"], function($, config) {
<<<<<<>>>>>> dev
    header = {
        borderless: true,
        cols: [{
            view: "toolbar",
            height: 66,
            css: "toolbar",
            cols: [
                { view: "template", borderless: true, template: "", width: 200 },
                { view: "template", template: "
DSA UberSlide Sorter
", borderless: true },
                {},
                { view: "template", borderless: true, template: "", width: 160 },
            ]
        }]
    };
    ///I may want to add back in the menu instead of {}----

    //Top LEvel will have three panels
    //Top is a View Bar
    //with a left panel for info and a bigger panel that allows us to switch views between a tab
    //and data table view
    slideListDataTable_Columns = [
        { id: "id", title: "ID", hidden: true},
        { id: "thumbnail", header: "Thumbnail", width: 100, template: "" },
        { id: "label", header: ["Label", { content: "serverFilter" }], width: 300, editor:"text"},
        { id: "set", header: ["Slide Set", { content: "serverSelectFilter" }], width: 200 },
        { id: "width", sort: "server", header: "Width", width: 80 },
        { id: "height", sort: "server", header: "Height", width: 80 },
        { id: "size", sort: "server", header: "Size", width: 100 },
        { id: "path", header: ["Slide Path", { content: "serverFilter" }], width: 400, fillspace: true },
        { id: "originalResolution", header: "Ori. Res.", width: 50 },
        { id: "openSlideSuccess", header: "OpenSlide Success", width: 100 },
    ]

    wbx_SlideListDataTable = {
        rows: [  { cols: [{
            view: "pager",
            template: "{common.first()} {common.prev()} {common.pages()} {common.next()} {common.last()} (Total Slides #count#)",
            container: "paging",
            size: 20,
            group: 5,
            id: "gridPager"
        }, {view:"template", template:"Template1 Template 2"}]},
        {
            id: "slidelist",
            view: "datatable",
            columns: slideListDataTable_Columns,
            url: config.BASE_URL + "/slides",
            select: true,
            navigation: true,
            pager: "gridPager",
            datafetch: 20,
            loadahead: 20,
            editable:true,
            editaction: "dblclick",
            on:{
                onAfterEditStop:function(state, editor){
                    if (state.value != state.old){
                        $.ajax({
                            url: config.BASE_URL + "/slide/" + editor.row,
                            method: "PUT",
                            contentType: "application/json",
                            dataType: "json",
                            data: JSON.stringify({"label": state.value}),
                            success: function(slide){
                                console.log(slide);
                            },
                            error: function(jqXHR){
                                console.log(jqXHR);
                            }
                        });
                    }
                }
            }
        }]
    }

    wbx_SlideDataView = {
        rows: [
            {
                view: "pager",
                id: "pagerA",
                size: 50,
                group: 5,
                template: "{common.first()} {common.prev()} {common.pages()} {common.next()} {common.last()} (Total Slides #count#)",
                datafetch: 50,
                loadahead: 50
            },
            {
                view: "dataview",
                select: true,

                template: "
#fileName#
Size: #width# x #height#",
                type: {
                    height: 150
                },
                url: config.BASE_URL + "/slides",
                pager: "pagerA"
            }
        ]
    }

    mainDataPanel = {
        view: "tabview",
        id: "wbxLeftPanel",

        cells: [

            { header: "GridView", body: { rows: [wbx_SlideListDataTable] } },

            {
                header: "DataTableView",
                body: {
                    rows: [{ template: "Controls could go here", height: 20 }, { view: 'resizer' }, wbx_SlideDataView]
                }
            },
            { header: "About", body: { id: "about", content: "about_text", } },
        ],
        tabbar: {
            on: {
                onAfterTabClick: function(id) {
                    webix.message(id)
                }
            }
        }
    };

    metaImageViewer = { view: "template", "content": "dv_imageReview", width: 200 };

    RawSlideLayout = {
        container: "main_layout",

        id: "mylayout",
        type: "space",
        rows: [
            header, //here you place any component you like

            { view: "resizer" },
            { cols: [metaImageViewer, mainDataPanel], fillspace: true }
        ]
    }

    webix.ready(function() {
        webix.ui(RawSlideLayout);
    });
});
<commit_msg>update<commit_after>define(["jquery", "config", "webix"], function($, config) {

    header = {
        borderless: true,
        cols: [{
            view: "toolbar",
            height: 66,
            css: "toolbar",
            cols: [
                { view: "template", borderless: true, template: "", width: 200 },
                { view: "template", template: "
DSA UberSlide Sorter
", borderless: true },
                {},
                { view: "template", borderless: true, template: "", width: 160 },
            ]
        }]
    };
    ///I may want to add back in the menu instead of {}----

    //Top LEvel will have three panels
    //Top is a View Bar
    //with a left panel for info and a bigger panel that allows us to switch views between a tab
    //and data table view
    slideListDataTable_Columns = [
        { id: "id", title: "ID", hidden: true},
        { id: "thumbnail", header: "Thumbnail", width: 100, template: "" },
        { id: "label", header: ["Label", { content: "serverFilter" }], width: 300, editor:"text"},
        { id: "set", header: ["Slide Set", { content: "serverSelectFilter" }], width: 200 },
        { id: "width", sort: "server", header: "Width", width: 80 },
        { id: "height", sort: "server", header: "Height", width: 80 },
        { id: "size", sort: "server", header: "Size", width: 100 },
        { id: "path", header: ["Slide Path", { content: "serverFilter" }], width: 400, fillspace: true },
        { id: "originalResolution", header: "Ori. Res.", width: 50 },
        { id: "openSlideSuccess", header: "OpenSlide Success", width: 100 },
    ]

    wbx_SlideListDataTable = {
        rows: [  { cols: [{
            view: "pager",
            template: "{common.first()} {common.prev()} {common.pages()} {common.next()} {common.last()} (Total Slides #count#)",
            container: "paging",
            size: 20,
            group: 5,
            id: "gridPager"
        }, {view:"template", template:"Template1 Template 2"}]},
        {
            id: "slidelist",
            view: "datatable",
            columns: slideListDataTable_Columns,
            url: config.BASE_URL + "/slides",
            select: true,
            navigation: true,
            pager: "gridPager",
            datafetch: 20,
            loadahead: 20,
            editable:true,
            editaction: "dblclick",
            on:{
                onAfterEditStop:function(state, editor){
                    if (state.value != state.old){
                        $.ajax({
                            url: config.BASE_URL + "/slide/" + editor.row,
                            method: "PUT",
                            contentType: "application/json",
                            dataType: "json",
                            data: JSON.stringify({"label": state.value}),
                            success: function(slide){
                                console.log(slide);
                            },
                            error: function(jqXHR){
                                console.log(jqXHR);
                            }
                        });
                    }
                }
            }
        }]
    }

    wbx_SlideDataView = {
        rows: [
            {
                view: "pager",
                id: "pagerA",
                size: 50,
                group: 5,
                template: "{common.first()} {common.prev()} {common.pages()} {common.next()} {common.last()} (Total Slides #count#)",
                datafetch: 50,
                loadahead: 50
            },
            {
                view: "dataview",
                select: true,

                template: "
#fileName#
Size: #width# x #height#",
                type: {
                    height: 150
                },
                url: config.BASE_URL + "/slides",
                pager: "pagerA"
            }
        ]
    }

    mainDataPanel = {
        view: "tabview",
        id: "wbxLeftPanel",

        cells: [

            { header: "GridView", body: { rows: [wbx_SlideListDataTable] } },

            {
                header: "DataTableView",
                body: {
                    rows: [{ template: "Controls could go here", height: 20 }, { view: 'resizer' }, wbx_SlideDataView]
                }
            },
            { header: "About", body: { id: "about", content: "about_text", } },
        ],
        tabbar: {
            on: {
                onAfterTabClick: function(id) {
                    webix.message(id)
                }
            }
        }
    };

    metaImageViewer = { view: "template", "content": "dv_imageReview", width: 200 };

    RawSlideLayout = {
        container: "main_layout",

        id: "mylayout",
        type: "space",
        rows: [
            header, //here you place any component you like

            { view: "resizer" },
            { cols: [metaImageViewer, mainDataPanel], fillspace: true }
        ]
    }

    webix.ready(function() {
        webix.ui(RawSlideLayout);
    });
});
<|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var tape = require( 'tape' );
var bundle = require( './../' );

// TESTS //

tape( 'main export is an object', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof bundle, 'object', 'main export is an object' );
	t.end();
});

tape( 'the object exposes a "flat" namespace', function test( t ) {
	t.equal( typeof bundle, 'object', 'main export is an object' );
	t.equal( typeof bundle.base, 'object', 'has member' );
	t.equal( bundle.base.sin( 3.14 ), 0.0015926529164868282, 'returns expected value' );
	t.end();
});
<commit_msg>Update test<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var tape = require( 'tape' );
var bundle = require( './../' );

// TESTS //

tape( 'main export is an object', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof bundle, 'object', 'main export is an object' );
	t.end();
});

tape( 'the object exposes a "flat" namespace', function test( t ) {
	t.equal( typeof bundle.base, 'object', 'has member' );
	t.equal( bundle.base.sin( 3.14 ), 0.0015926529164868282, 'returns expected value' );
	t.end();
});
<|endoftext|>


<commit_before>var attachments_ui = (function () {

var exports = {};

var attachments;

function delete_attachments(attachment) {
    var status = $('#delete-upload-status');
    channel.del({
        url: '/json/attachments/' + attachment,
        idempotent: true,
        error: function (xhr) {
            ui_report.error(i18n.t("Failed"), xhr, status);
        },
        success: function () {
            ui_report.success(i18n.t("Attachment deleted"), status);
        },
    });
}

function bytes_to_size(bytes, kb_with_1024_bytes) {
    if (kb_with_1024_bytes === undefined) {
        kb_with_1024_bytes = false;
    }
    var kb_size = kb_with_1024_bytes ? 1024 : 1000;
    var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    if (bytes === 0) {
        return '0 B';
    }
    var i = parseInt(Math.floor(Math.log(bytes) / Math.log(kb_size)), 10);
    var size = Math.round(bytes / Math.pow(kb_size, i));
    if (i > 0 && size < 10) {
        size = Math.round(bytes / Math.pow(kb_size, i) * 10) / 10;
    }
    return size + ' ' + sizes[i];
}

function render_attachments_ui() {
    var uploaded_files_table = $("#uploaded_files_table").expectOne();
    var $search_input = $("#upload_file_search");

    var list = list_render.create(uploaded_files_table, attachments, {
        name: "uploaded-files-list",
        modifier: function (attachment) {
            return templates.render("uploaded_files_list", { attachment: attachment });
        },
        filter: {
            element: $search_input,
            callback: function (item, value) {
                return item.name.toLocaleLowerCase().indexOf(value) >= 0;
            },
            onupdate: function () {
                ui.update_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));
            },
        },
        parent_container: $('#attachments-settings').expectOne(),
    }).init();

    list.add_sort_function("mentioned-in", function (a, b) {
        var a_m = a.messages[0];
        var b_m = b.messages[0];

        if (!a_m) { return 1; }
        if (!b_m) { return -1; }

        if (a_m.id > b_m.id) {
            return 1;
        } else if (a_m.id === b_m.id) {
            return 0;
        }

        return -1;
    });

    ui.update_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));
}

function format_attachment_data(new_attachments) {
    _.each(new_attachments, function (attachment) {
        var time = new XDate(attachment.create_time);
        attachment.create_time_str = timerender.render_now(time).time_str;
        attachment.size_str = bytes_to_size(attachment.size);
    });
}

exports.update_attachments = function (event) {
    if (attachments === undefined) {
        // If we haven't fetched attachment data yet, there's nothing to do.
        return;
    }
    if (event.op === 'remove' || event.op === 'update') {
        attachments = attachments.filter(function (a) {
            return a.id !== event.attachment.id;
        });
    }
    if (event.op === 'add' || event.op === 'update') {
        format_attachment_data([event.attachment]);
        attachments.push(event.attachment);
    }

    // TODO: This is inefficient and we should be able to do some sort
    // of incremental list_render update instead.
    render_attachments_ui();
};

exports.set_up_attachments = function () {
    // The settings page must be rendered before this function gets called.

    var uploaded_files_table = $("#uploaded_files_table").expectOne();
    var status = $('#delete-upload-status');
    loading.make_indicator($('#attachments_loading_indicator'), {text: 'Loading...'});

    ui.set_up_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));

    $('#uploaded_files_table').on('click', '.remove-attachment', function (e) {
        delete_attachments($(e.target).closest(".uploaded_file_row").attr('data-attachment-id'));
    });

    channel.get({
        url: "/json/attachments",
        idempotent: true,
        success: function (data) {
            loading.destroy_indicator($('#attachments_loading_indicator'));
            format_attachment_data(data.attachments);
            attachments = data.attachments;
            render_attachments_ui();
        },
        error: function (xhr) {
            loading.destroy_indicator($('#attachments_loading_indicator'));
            ui_report.error(i18n.t("Failed"), xhr, status);
        },
    });
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = attachments_ui;
}
window.attachments_ui = attachments_ui;
<commit_msg>attachments ui: Initialize table sorted by Date uploaded column.<commit_after>var attachments_ui = (function () {

var exports = {};

var attachments;

function delete_attachments(attachment) {
    var status = $('#delete-upload-status');
    channel.del({
        url: '/json/attachments/' + attachment,
        idempotent: true,
        error: function (xhr) {
            ui_report.error(i18n.t("Failed"), xhr, status);
        },
        success: function () {
            ui_report.success(i18n.t("Attachment deleted"), status);
        },
    });
}

function bytes_to_size(bytes, kb_with_1024_bytes) {
    if (kb_with_1024_bytes === undefined) {
        kb_with_1024_bytes = false;
    }
    var kb_size = kb_with_1024_bytes ? 1024 : 1000;
    var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    if (bytes === 0) {
        return '0 B';
    }
    var i = parseInt(Math.floor(Math.log(bytes) / Math.log(kb_size)), 10);
    var size = Math.round(bytes / Math.pow(kb_size, i));
    if (i > 0 && size < 10) {
        size = Math.round(bytes / Math.pow(kb_size, i) * 10) / 10;
    }
    return size + ' ' + sizes[i];
}

function render_attachments_ui() {
    var uploaded_files_table = $("#uploaded_files_table").expectOne();
    var $search_input = $("#upload_file_search");

    var list = list_render.create(uploaded_files_table, attachments, {
        name: "uploaded-files-list",
        modifier: function (attachment) {
            return templates.render("uploaded_files_list", { attachment: attachment });
        },
        filter: {
            element: $search_input,
            callback: function (item, value) {
                return item.name.toLocaleLowerCase().indexOf(value) >= 0;
            },
            onupdate: function () {
                ui.update_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));
            },
        },
        parent_container: $('#attachments-settings').expectOne(),
    }).init();

    list.sort('numeric', 'create_time');

    list.add_sort_function("mentioned-in", function (a, b) {
        var a_m = a.messages[0];
        var b_m = b.messages[0];

        if (!a_m) { return 1; }
        if (!b_m) { return -1; }

        if (a_m.id > b_m.id) {
            return 1;
        } else if (a_m.id === b_m.id) {
            return 0;
        }

        return -1;
    });

    ui.update_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));
}

function format_attachment_data(new_attachments) {
    _.each(new_attachments, function (attachment) {
        var time = new XDate(attachment.create_time);
        attachment.create_time_str = timerender.render_now(time).time_str;
        attachment.size_str = bytes_to_size(attachment.size);
    });
}

exports.update_attachments = function (event) {
    if (attachments === undefined) {
        // If we haven't fetched attachment data yet, there's nothing to do.
        return;
    }
    if (event.op === 'remove' || event.op === 'update') {
        attachments = attachments.filter(function (a) {
            return a.id !== event.attachment.id;
        });
    }
    if (event.op === 'add' || event.op === 'update') {
        format_attachment_data([event.attachment]);
        attachments.push(event.attachment);
    }

    // TODO: This is inefficient and we should be able to do some sort
    // of incremental list_render update instead.
    render_attachments_ui();
};

exports.set_up_attachments = function () {
    // The settings page must be rendered before this function gets called.

    var uploaded_files_table = $("#uploaded_files_table").expectOne();
    var status = $('#delete-upload-status');
    loading.make_indicator($('#attachments_loading_indicator'), {text: 'Loading...'});

    ui.set_up_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));

    $('#uploaded_files_table').on('click', '.remove-attachment', function (e) {
        delete_attachments($(e.target).closest(".uploaded_file_row").attr('data-attachment-id'));
    });

    channel.get({
        url: "/json/attachments",
        idempotent: true,
        success: function (data) {
            loading.destroy_indicator($('#attachments_loading_indicator'));
            format_attachment_data(data.attachments);
            attachments = data.attachments;
            render_attachments_ui();
        },
        error: function (xhr) {
            loading.destroy_indicator($('#attachments_loading_indicator'));
            ui_report.error(i18n.t("Failed"), xhr, status);
        },
    });
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = attachments_ui;
}
window.attachments_ui = attachments_ui;
<|endoftext|>